{"id":33839,"date":"2019-10-31T21:54:56","date_gmt":"2019-10-31T18:54:56","guid":{"rendered":"https:\/\/prohoster.info\/blog\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov\/"},"modified":"2019-10-31T21:54:56","modified_gmt":"2019-10-31T18:54:56","slug":"objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sq\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","title":{"rendered":"ObjectRepository \u2014 nj\u00eb model depozite n\u00eb memorie .NET p\u00ebr projektet tuaja n\u00eb sht\u00ebpi.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2 id=\"zachem-hranit-vse-dannye-v-pamyati\">Pse t\u00eb ruani t\u00eb gjitha t\u00eb dh\u00ebnat n\u00eb memorie?<\/h2>\n<p><\/p>\n<p>P\u00ebr ruajtjen e t\u00eb dh\u00ebnave t\u00eb faqes ose backend-it, d\u00ebshira e par\u00eb e shumic\u00ebs s\u00eb njer\u00ebzve me mendje t\u00eb sh\u00ebndosh\u00eb do t\u00eb jet\u00eb t\u00eb zgjidhin nj\u00eb baz\u00eb t\u00eb dh\u00ebnash SQL.\u00a0<\/p>\n<p><\/p>\n<p>Por ndonj\u00ebher\u00eb n\u00eb mendje vjen ideja q\u00eb modeli i t\u00eb dh\u00ebnave nuk i p\u00ebrshtatet SQL: p\u00ebr shembull, kur nd\u00ebrtosh k\u00ebrkimin ose grafik\u00ebn sociale, nevojitet k\u00ebrkimi mbi lidhjet komplekse midis objekteve.\u00a0<\/p>\n<p><\/p>\n<p><strong>Situata m\u00eb e keqe \u00ebsht\u00eb kur punoni n\u00eb nj\u00eb ekip dhe nj\u00eb koleg nuk di t\u00eb nd\u00ebrtoj\u00eb k\u00ebrkesa t\u00eb shpejta. Sa koh\u00eb keni harxhuar p\u00ebr t\u00eb zgjidhur problemet N+1 dhe p\u00ebr nd\u00ebrtimin e indekseve t\u00eb tjera, q\u00eb SELECT n\u00eb faqen kryesore t\u00eb punoj\u00eb brenda nj\u00eb kohe t\u00eb arsyeshme?<\/strong><\/p>\n<p><\/p>\n<p>Nj\u00eb qasje tjet\u00ebr e njohur \u00ebsht\u00eb NoSQL. Para disa vitesh kishte nj\u00eb bum t\u00eb madh rreth k\u00ebsaj teme \u2014 p\u00ebr \u00e7do rast t\u00eb p\u00ebrshtatsh\u00ebm, u instalonte MongoDB dhe g\u00ebzoheshin me p\u00ebrgjigjet n\u00eb form\u00ebn e dokumenteve json <em>(p.s. sa shum\u00eb ndihma iu desh t\u00eb vendosni p\u00ebr shkak t\u00eb lidhjeve ciklike n\u00eb dokumente?)<\/em>.<\/p>\n<p><\/p>\n<p>Un\u00eb sugjeroj t\u00eb provoni nj\u00eb m\u00ebnyr\u00eb tjet\u00ebr, alternative \u2014 pse t\u00eb mos provoni t\u00eb ruani t\u00eb gjitha t\u00eb dh\u00ebnat n\u00eb memorie t\u00eb aplikacionit, duke i ruajtur periudh\u00ebsisht n\u00eb nj\u00eb depo t\u00eb rast\u00ebsishme (skedari, baz\u00eb t\u00eb dh\u00ebnash t\u00eb larg\u00ebt)?\u00a0<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Memoria \u00ebsht\u00eb b\u00ebr\u00eb e lir\u00eb, dhe \u00e7do t\u00eb dh\u00ebn\u00eb e mundshme p\u00ebr shumic\u00ebn e projekteve t\u00eb vogla dhe t\u00eb mesme do t\u00eb hyj\u00eb n\u00eb 1 GB memorie. <em>(P\u00ebr shembull, projekti im i preferuar n\u00eb sht\u00ebpi \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/BudgetTracker\">ndjek\u00ebsi financiar<\/a><\/noindex>, i cili mban statistikat dhe historin\u00eb e shpenzimeve, balancave dhe transaksioneve t\u00eb mia p\u00ebr nj\u00eb vit e gjysm\u00eb, konsumon vet\u00ebm 45 MB memorie.)<\/em><\/p>\n<p><\/p>\n<p>Avantazhet:<\/p>\n<p><\/p>\n<ul>\n<li>Qakses n\u00eb t\u00eb dh\u00ebna b\u00ebhet m\u00eb e leht\u00eb \u2014 nuk nevojitet t\u00eb merremi me k\u00ebrkesat, ngarkimin e ngadalsh\u00ebm, ve\u00e7orit\u00eb e ORM-s\u00eb, puna b\u00ebhet me objekte t\u00eb zakonshme C#;<\/li>\n<li>Nuk ka probleme t\u00eb lidhura me qasjen nga fibra t\u00eb ndryshme;<\/li>\n<li>Shum\u00eb shpejt \u2014 nuk ka k\u00ebrkesa n\u00eb rrjet, nuk ka translacion t\u00eb kodit n\u00eb gjuh\u00ebn e k\u00ebrkesave, nuk \u00ebsht\u00eb e nevojshme t\u00eb (de)serializoni objektet;<\/li>\n<li>Pranohet t\u00eb ruani t\u00eb dh\u00ebnat n\u00eb \u00e7do format \u2014 qoft\u00eb n\u00eb XML n\u00eb disku, qoft\u00eb n\u00eb SQL Server, qoft\u00eb n\u00eb Azure Table Storage.<\/li>\n<\/ul>\n<p><\/p>\n<p>Disavantazhet:<\/p>\n<p><\/p>\n<ul>\n<li>Humbet shkall\u00ebzimi horizontal dhe si pasoj\u00eb nuk mund t\u00eb realizoni nj\u00eb rikthim zero n\u00eb ndjekje;<\/li>\n<li>N\u00ebse aplikacioni d\u00ebshton \u2014 mund t\u00eb humbni pjes\u00ebrisht t\u00eb dh\u00ebnat. <em>(Por aplikacioni yn\u00eb kurr\u00eb nuk d\u00ebshton, apo jo?)<\/em><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Si funksionon kjo?<\/h2>\n<p><\/p>\n<p>Algoritmi \u00ebsht\u00eb si m\u00eb posht\u00eb:<\/p>\n<p><\/p>\n<ul>\n<li>Fillimisht krijohet lidhja me depot e t\u00eb dh\u00ebnave, dhe ndodh ngarkimi i t\u00eb dh\u00ebnave;<\/li>\n<li>Nd\u00ebrtohet modeli objektor, indekset primare dhe indekset e lidhjeve (1:1, 1:M many).<\/li>\n<li>Krijohet nj\u00eb abonim p\u00ebr ndryshimet e pronave t\u00eb objekteve (INotifyPropertyChanged) dhe p\u00ebr shtimin ose heqjen e elementeve n\u00eb koleksion (INotifyCollectionChanged);<\/li>\n<li>Kur ndodh abonimi \u2014 objekti i ndryshuar shtohet n\u00eb radh\u00ebn p\u00ebr regjistrim n\u00eb magazin\u00ebn e t\u00eb dh\u00ebnave;<\/li>\n<li>Periodikisht (n\u00eb nj\u00eb timer) n\u00eb procesin e prapambetjes regjistrohen ndryshimet n\u00eb magazin\u00eb;<\/li>\n<li>Edhe kur del nga aplikacioni regjistrohen ndryshimet n\u00eb magazin\u00eb.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"primer-koda\">Shembulli i kodit<\/h2>\n<p>\n<b class=\"spoiler_title\">Shtojm\u00eb var\u00ebsit\u00eb e nevojshme<\/b><\/p>\n<pre><code class=\"cs\">\/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\nInstall-Package OutCode.EscapeTeams.ObjectRepository\n\u00a0 \u00a0\u00a0\n\/\/ \u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\n\/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0442\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0435\u0442\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f.\nInstall-Package OutCode.EscapeTeams.ObjectRepository.File\nInstall-Package OutCode.EscapeTeams.ObjectRepository.LiteDb\nInstall-Package OutCode.EscapeTeams.ObjectRepository.AzureTableStorage\n\u00a0 \u00a0\u00a0\n\/\/ \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e - \u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f Hangfire\n\/\/ Install-Package OutCode.EscapeTeams.ObjectRepository.Hangfire<\/code><\/pre>\n<p>\n<b class=\"spoiler_title\">P\u00ebrshkruajm\u00eb modelin e t\u00eb dh\u00ebnave q\u00eb do t\u00eb ruhet n\u00eb magazin\u00eb<\/b><\/p>\n<pre><code class=\"cs\">public class ParentEntity : BaseEntity\n{\n    public ParentEntity(Guid id) =&gt; Id = id;\n}\n    \npublic class ChildEntity : BaseEntity\n{\n    public ChildEntity(Guid id) =&gt; Id = id;\n    public Guid ParentId { get; set; }\n    public string Value { get; set; }\n}<\/code><\/pre>\n<p>\n<b class=\"spoiler_title\">Pastaj modeli objektiv:<\/b><\/p>\n<pre><code class=\"cs\">public class ParentModel : ModelBase\n{\n    public ParentModel(ParentEntity entity)\n    {\n        Entity = entity;\n    }\n    \n    public ParentModel()\n    {\n        Entity = new ParentEntity(Guid.NewGuid());\n    }\n    \n    public Guid? NullableId =&gt; null;\n    \n    \/\/ Shembulli i lidhjes 1:M\n    public IEnumerable Children =&gt; Multiple(x =&gt; x.ParentId);\n    \n    protected override BaseEntity Entity { get; }\n}\n    \npublic class ChildModel : ModelBase\n{\n    private ChildEntity _childEntity;\n    \n    public ChildModel(ChildEntity entity)\n    {\n        _childEntity = entity;\n    }\n    \n    public ChildModel() \n    {\n        _childEntity = new ChildEntity(Guid.NewGuid());\n    }\n    \n    public Guid ParentId\n    {\n        get =&gt; _childEntity.ParentId;\n        set =&gt; UpdateProperty(() =&gt; _childEntity.ParentId, value);\n    }\n    \n    public string Value\n    {\n        get =&gt; _childEntity.Value;\n        set =&gt; UpdateProperty(() =&gt; _childEntity.Value, value\n    }\n    \n    \/\/ Qasje me k\u00ebrkes\u00eb sipas indeksit\n    public ParentModel Parent =&gt; Single(ParentId);\n    \n    protected override BaseEntity Entity =&gt; _childEntity;\n}<\/code><\/pre>\n<p>\n<b class=\"spoiler_title\">Dhe p\u00ebrfundimisht klasa-repozita p\u00ebr qasje n\u00eb t\u00eb dh\u00ebna:<\/b><\/p>\n<pre><code class=\"cs\">public class MyObjectRepository : ObjectRepositoryBase\n{\n    public MyObjectRepository(IStorage storage) : base(storage, NullLogger.Instance)\n    {\n        IsReadOnly = true; \/\/ P\u00ebr teste, lejon q\u00eb t\u00eb mos ruaj\u00eb ndryshimet n\u00eb baz\u00eb\n    \n        AddType((ParentEntity x) =&gt; new ParentModel(x));\n        AddType((ChildEntity x) =&gt; new ChildModel(x));\n    \n        \/\/ N\u00ebse p\u00ebrdoret Hangfire dhe duhet t\u00eb mbahen modelet e t\u00eb dh\u00ebnave p\u00ebr Hangfire n\u00eb ObjectRepository\n        \/\/ this.RegisterHangfireScheme();  \n    \n        Initialize();\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>Krijojm\u00eb nj\u00eb instanc\u00eb t\u00eb ObjectRepository:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">var memory = new MemoryStream();\nvar db = new LiteDatabase(memory);\nvar dbStorage = new LiteDbStorage(db);\n    \nvar repository = new MyObjectRepository(dbStorage);\nawait repository.WaitForInitialize();<\/code><\/pre>\n<p>\n<b class=\"spoiler_title\">N\u00ebse projekti do t\u00eb p\u00ebrdor\u00eb HangFire<\/b><\/p>\n<pre><code class=\"cs\">public void ConfigureServices(IServiceCollection services, ObjectRepository objectRepository)\n{\n    services.AddHangfire(s =&gt; s.UseHangfireStorage(objectRepository));\n}<\/code><\/pre>\n<p><\/p>\n<p>Shtimi i nj\u00eb objekti t\u00eb ri:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">var newParent = new ParentModel()\nrepository.Add(newParent);<\/code><\/pre>\n<p><\/p>\n<p>Me kjo thirrje objekti <strong>ParentModel<\/strong> shtohet si n\u00eb cache lokal ashtu edhe n\u00eb radh\u00ebn p\u00ebr shkrim n\u00eb baz\u00eb. K\u00ebshtu q\u00eb kjo operacion z\u00eb O(1), dhe mund t\u00eb punoni menj\u00ebher\u00eb me k\u00ebt\u00eb objekt.<\/p>\n<p><\/p>\n<p>P\u00ebr shembull, p\u00ebr t\u00eb gjetur k\u00ebt\u00eb objekt n\u00eb depo dhe p\u00ebr t'u siguruar q\u00eb objekti i kthyer \u00ebsht\u00eb po ai ekzemplar:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">var parents = repository.Set();\nvar myParent = parents.Find(newParent.Id);\nAssert.IsTrue(ReferenceEquals(myParent, newParent));<\/code><\/pre>\n<p><\/p>\n<p>\u00c7far\u00eb ndodh gjat\u00eb k\u00ebsaj? <em>Set()<\/em> false, n\u00ebse elementi q\u00eb do t\u00eb z\u00ebvend\u00ebsohet \u00ebsht\u00eb <em>TableDictionary<\/em>, e cila p\u00ebrmban brenda saj <em>ConcurrentDictionary<\/em> dhe ofron funksionalitete shtes\u00eb p\u00ebr indekset primare dhe sekondare. Kjo lejon q\u00eb t\u00eb kemi metoda p\u00ebr k\u00ebrkimin sipas Id (ose indekseve t\u00eb tjera t\u00eb rastit) pa k\u00ebrkime t\u00eb plota mbi t\u00eb gjith\u00eb objektet.<\/p>\n<p><\/p>\n<p>Kur shtohen objektet n\u00eb <em>ObjectRepository<\/em> shtohet nj\u00eb abonim p\u00ebr ndryshimin e pronave t\u00eb tyre, prandaj \u00e7do ndryshim i pronave gjithashtu \u00e7on n\u00eb shtimin e k\u00ebtij objekti n\u00eb radh\u00ebn p\u00ebr shkrim.\u00a0<br \/>\nP\u00ebrdit\u00ebsimi i pronave nga jasht\u00eb duket si puna me nj\u00eb objekt POCO:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">myParent.Children.First().Property = \"Vlera e p\u00ebrdit\u00ebsuar\";<\/code><\/pre>\n<p><\/p>\n<p>Objekti mund t\u00eb fshihet n\u00eb m\u00ebnyra t\u00eb ndryshme:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">repository.Remove(myParent);\nrepository.RemoveRange(otherParents);\nrepository.Remove(x =&gt; !x.Children.Any());<\/code><\/pre>\n<p><\/p>\n<p>Gjat\u00eb k\u00ebsaj ndodh gjithashtu shtimi i objektit n\u00eb radh\u00ebn p\u00ebr fshirje.<\/p>\n<p><\/p>\n<h2 id=\"kak-rabotaet-sohranenie\">Si funksionon ruajtja?<\/h2>\n<p><\/p>\n<p><em>ObjectRepository<\/em> ndryshimi i objekteve t\u00eb ndjekura (si shtimi apo fshirja, ashtu edhe ndryshimi i pronave) th\u00ebrret nj\u00eb ngjarje <em>ModelChanged<\/em>, n\u00eb t\u00eb cil\u00ebn \u00ebsht\u00eb regjistruar <em>IStorage<\/em>. Zbatimet <em>IStorage<\/em> kur ndodh ngjarja <em>ModelChanged<\/em> grupojn\u00eb ndryshimet n\u00eb 3 radh\u00eb - p\u00ebr shtim, p\u00ebr p\u00ebrdit\u00ebsim, dhe p\u00ebr fshirje.<\/p>\n<p><\/p>\n<p>Po ashtu, zbatimet <em>IStorage<\/em> n\u00eb fillim krijojn\u00eb nj\u00eb timer, i cili \u00e7do 5 sekonda th\u00ebrret ruajtjen e ndryshimeve.\u00a0<\/p>\n<p><\/p>\n<p><em>P\u00ebr m\u00eb tep\u00ebr, ka nj\u00eb API p\u00ebr thirrjen e detyruar t\u00eb ruajtjes: <strong>ObjectRepository.Save()<\/strong>.<\/em><\/p>\n<p><\/p>\n<p>Para \u00e7do ruajtjeje, s\u00eb pari ndodh fshirja nga radh\u00ebt e operacioneve t\u00eb pavlera (p\u00ebr shembull, dublikatet e ngjarjeve - kur objekti \u00ebsht\u00eb nd\u00ebrruar dy her\u00eb ose shtimi\/fshirja e shpejt\u00eb e objekteve), dhe vet\u00ebm pastaj ruajtja vet\u00eb.\u00a0<\/p>\n<p><\/p>\n<p><em>N\u00eb t\u00eb gjitha rastet ruhet objekti aktual n\u00eb t\u00ebr\u00ebsi, prandaj \u00ebsht\u00eb e mundur q\u00eb objektet t\u00eb ruhen n\u00eb nj\u00eb rend tjet\u00ebr nga sa u nd\u00ebrruan, duke p\u00ebrfshir\u00eb ruajtjen e versioneve m\u00eb t\u00eb reja t\u00eb objekteve, sesa n\u00eb momentin e shtimit n\u00eb radh\u00eb.<\/em><\/p>\n<p><\/p>\n<h2 id=\"chto-est-eschyo\">\u00c7far\u00eb tjet\u00ebr ka?<\/h2>\n<p><\/p>\n<ul>\n<li>T\u00eb gjitha bibliotekat jan\u00eb t\u00eb bazuara n\u00eb .NET Standard 2.0. Mund t\u00eb p\u00ebrdoren n\u00eb \u00e7do projekt modern .NET.<\/li>\n<li>API \u00ebsht\u00eb i sigurt p\u00ebr p\u00ebrdorim n\u00eb m\u00ebnyr\u00eb t\u00eb p\u00ebrbashk\u00ebt. Koleksionet e brendshme jan\u00eb zbatuar mbi <em>ConcurrentDictionary<\/em>, handlerat e ngjarjeve kan\u00eb gjithashtu bllokime ose nuk kan\u00eb nevoj\u00eb p\u00ebr to.\u00a0<br \/>\nE vetmja gj\u00eb q\u00eb duhet t\u00eb mbani mend \u00ebsht\u00eb t\u00eb th\u00ebrrisni <em>ObjectRepository.Save();<\/em><\/li>\n<li>Indekset arbitrare (k\u00ebrkojn\u00eb unik\u00ebsin\u00eb):<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"cs\">repository.Set&lt;ChildModel&gt;().AddIndex(x =&gt; x.Value);\nrepository.Set&lt;ChildModel&gt;().Find(x =&gt; x.Value, \"myValue\");<\/code><\/pre>\n<p><\/p>\n<h2 id=\"kto-eto-ispolzuet\">Kush e p\u00ebrdor k\u00ebt\u00eb?<\/h2>\n<p><\/p>\n<p>Personalish, kam filluar ta p\u00ebrdor k\u00ebt\u00eb qasje n\u00eb t\u00eb gjitha projektet e mia si hobi, sepse \u00ebsht\u00eb e p\u00ebrshtatshme dhe nuk k\u00ebrkon shum\u00eb investime n\u00eb zhvillimin e nj\u00eb Leveli t\u00eb Qasjes n\u00eb t\u00eb Dh\u00ebna apo krijimin e nj\u00eb infrastrukture t\u00eb r\u00ebnd\u00eb. M\u00eb p\u00ebrgjith\u00ebsi, mjafton p\u00ebr mua ruajtja e t\u00eb dh\u00ebnave n\u00eb litedb ose n\u00eb nj\u00eb skedar.\u00a0<\/p>\n<p><\/p>\n<p>Por n\u00eb t\u00eb kaluar\u00ebn, kur me ekipin b\u00ebjm\u00eb start-up-in tani t\u00eb ndalur EscapeTeams (<em>mendoja se k\u00ebtu jan\u00eb, parat\u00eb \u2013 por jo, p\u00ebrs\u00ebri p\u00ebrvoj\u00eb<\/em>) \u2013 p\u00ebrdornim Azure Table Storage p\u00ebr ruajtjen e t\u00eb dh\u00ebnave.<\/p>\n<p><\/p>\n<h2 id=\"plany-na-buduschee\">Planet p\u00ebr t\u00eb ardhmen<\/h2>\n<p><\/p>\n<p>D\u00ebshiroj t\u00eb rregulloj nj\u00eb nga disavantazhet kryesore t\u00eb k\u00ebtij qasjeje \u2013 shkall\u00ebzimi horizontal. P\u00ebr k\u00ebt\u00eb nevojiten ose transaksione t\u00eb shp\u00ebrndara (sic!), ose t\u00eb merret nj\u00eb vendim se t\u00eb nj\u00ebjtat t\u00eb dh\u00ebna nga instanca t\u00eb ndryshme nuk duhet t\u00eb ndryshojn\u00eb, ose le t\u00eb ndryshojn\u00eb sipas parimit 'kush \u00ebsht\u00eb i fundit \u2013 ai \u00ebsht\u00eb i sakt\u00eb'.<\/p>\n<p><\/p>\n<p>Nga pik\u00ebpamja teknike, shoh si t\u00eb mundshme skem\u00ebn e m\u00ebposhtme:<\/p>\n<p><\/p>\n<ul>\n<li>T\u00eb ruajm\u00eb n\u00eb vend t\u00eb modelit objektiv EventLog dhe Snapshot<\/li>\n<li>T\u00eb gjejm\u00eb instanca t\u00eb tjera (t\u00eb shtojm\u00eb n\u00eb cil\u00ebsimet e pikave t\u00eb fundit t\u00eb t\u00eb gjitha instancave? zbulimi UDP? master\/slave?)<\/li>\n<li>T\u00eb riplikojm\u00eb midis instancave EventLog p\u00ebrmes ndonj\u00eb prej algoritmeve t\u00eb konsensusit, p\u00ebr shembull RAFT.<\/li>\n<\/ul>\n<p><\/p>\n<p>Ka gjithashtu nj\u00eb problem tjet\u00ebr q\u00eb m\u00eb shqet\u00ebson \u2013 \u00ebsht\u00eb fshirja kaskad\u00eb, ose zbulimi i rasteve t\u00eb fshirjes s\u00eb objekteve q\u00eb kan\u00eb referenca nga objekte t\u00eb tjera.\u00a0<\/p>\n<p><\/p>\n<h2 id=\"ishodnyy-kod\">Kodi burimor<\/h2>\n<p><\/p>\n<p>N\u00ebse keni arritur deri k\u00ebtu \u2013 at\u00ebher\u00eb e ardhmja mbetet vet\u00ebm t\u00eb lexoni kodin, mund ta gjeni n\u00eb GitHub:<br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/ObjectRepository\">https:\/\/github.com\/DiverOfDark\/ObjectRepository<\/a><\/noindex><\/p>\n<p>Burimi: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/452232\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0417\u0430\u0447\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438? \u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0430\u0439\u0442\u0430 \u0438\u043b\u0438 \u0431\u0435\u043a\u044d\u043d\u0434\u0430 \u043f\u0435\u0440\u0432\u044b\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0437\u0434\u0440\u0430\u0432\u043e\u043c\u044b\u0441\u043b\u044f\u0449\u0438\u0445 \u043b\u044e\u0434\u0435\u0439 \u0432\u044b\u0431\u0435\u0440\u0435\u0442 SQL \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.\u00a0 \u041d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043c\u044b\u0441\u043b\u044c \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f SQL: \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438\u043b\u0438 \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0444\u0430 \u043d\u0443\u0436\u0435\u043d \u043f\u043e\u0438\u0441\u043a \u043f\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0441\u0432\u044f\u0437\u044f\u043c \u043c\u0435\u0436\u0434\u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438.\u00a0 \u0425\u0443\u0436\u0435 \u0432\u0441\u0435\u0433\u043e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[702],"tags":[],"class_list":["post-33839","post","type-post","status-publish","format-standard","hentry","category-news"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0417\u0430\u0447\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438? \u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0430\u0439\u0442\u0430 \u0438\u043b\u0438 \u0431\u0435\u043a\u044d\u043d\u0434\u0430 \u043f\u0435\u0440\u0432\u044b\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0437\u0434\u0440\u0430\u0432\u043e\u043c\u044b\u0441\u043b\u044f\u0449\u0438\u0445 \u043b\u044e\u0434\u0435\u0439 \u0432\u044b\u0431\u0435\u0440\u0435\u0442 SQL \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sq\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"sq_AL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47ObjectRepository \u2014 .NET in-memory repository pattern \u0434\u043b\u044f \u0432\u0430\u0448\u0438\u0445 \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0417\u0430\u0447\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438? \u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0430\u0439\u0442\u0430 \u0438\u043b\u0438 \u0431\u0435\u043a\u044d\u043d\u0434\u0430 \u043f\u0435\u0440\u0432\u044b\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0437\u0434\u0440\u0430\u0432\u043e\u043c\u044b\u0441\u043b\u044f\u0449\u0438\u0445 \u043b\u044e\u0434\u0435\u0439 \u0432\u044b\u0431\u0435\u0440\u0435\u0442 SQL \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sq\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:54:56+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:54:56+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47ObjectRepository \u2014 pattern i repositorios n\u00eb memorje .NET p\u00ebr projektet tuaja n\u00eb sht\u00ebpi | ProHoster","description":"Pse e mbani t\u00eb gjith\u00eb t\u00eb dh\u00ebnat n\u00eb kujtes\u00eb? P\u00ebr ruajtjen e t\u00eb dh\u00ebnave t\u00eb faqes ose t\u00eb backend, d\u00ebshira e par\u00eb e shumic\u00ebs s\u00eb njer\u00ebzve me mendje t\u00eb sh\u00ebndosh\u00eb \u00ebsht\u00eb t\u00eb zgjidhin nj\u00eb baz\u00eb t\u00eb dh\u00ebnash SQL.","canonical_url":"https:\/\/prohoster.info\/sq\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sq_AL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47ObjectRepository \u2014 .NET in-memory repository pattern \u0434\u043b\u044f \u0432\u0430\u0448\u0438\u0445 \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 | ProHoster","og:description":"\u0417\u0430\u0447\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438? \u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0430\u0439\u0442\u0430 \u0438\u043b\u0438 \u0431\u0435\u043a\u044d\u043d\u0434\u0430 \u043f\u0435\u0440\u0432\u044b\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0437\u0434\u0440\u0430\u0432\u043e\u043c\u044b\u0441\u043b\u044f\u0449\u0438\u0445 \u043b\u044e\u0434\u0435\u0439 \u0432\u044b\u0431\u0435\u0440\u0435\u0442 SQL \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.","og:url":"https:\/\/prohoster.info\/sq\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:54:56+00:00","article:modified_time":"2019-10-31T18:54:56+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"33839","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 16:56:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:32:27","updated":"2026-01-21 16:56:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/33839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/comments?post=33839"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/33839\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media?parent=33839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/categories?post=33839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/tags?post=33839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}