{"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\/lv\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","title":{"rendered":"ObjectRepository \u2014 .NET iek\u0161\u0113j\u0101 atmi\u0146as kr\u0101tuves modelis j\u016bsu m\u0101jas projektiem","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2 id=\"zachem-hranit-vse-dannye-v-pamyati\">K\u0101p\u0113c uzglab\u0101t visus datus atmi\u0146\u0101?<\/h2>\n<p><\/p>\n<p>Kad runa ir par m\u0101jaslapas vai aizmugur\u0113j\u0101s puses datu uzglab\u0101\u0161anu, vairums sapr\u0101t\u012bgu cilv\u0113ku pirm\u0101 izv\u0113le ir SQL datub\u0101ze.\u00a0<\/p>\n<p><\/p>\n<p>Bet da\u017ereiz pr\u0101t\u0101 ien\u0101k doma, ka datu modelis nav piem\u0113rots SQL: piem\u0113ram, veidojot mekl\u0113\u0161anu vai soci\u0101lo grafiku, nepiecie\u0161ama sare\u017e\u0123\u012btu attiec\u012bbu starp objektiem mekl\u0113\u0161ana.\u00a0<\/p>\n<p><\/p>\n<p><strong>Visgr\u016bt\u0101k ir str\u0101d\u0101jot komand\u0101, kad kol\u0113\u0123is nezina, k\u0101 veidot \u0101trus vaic\u0101jumus. Cik daudz laika esat pavad\u012bjis, risinot N+1 probl\u0113mas un veidojot papildus indeksus, lai SELECT galvenaj\u0101 lap\u0101 izpild\u012btos sapr\u0101t\u012bg\u0101 laik\u0101?<\/strong><\/p>\n<p><\/p>\n<p>Cits popul\u0101rs pieejas veids ir NoSQL. Pirms da\u017eiem gadiem ap \u0161o t\u0113mu bija liela a\u017eiot\u0101\u017ea \u2014 jebkur\u0101 izdev\u012bg\u0101 gad\u012bjum\u0101 tika izv\u0113rsta MongoDB un priec\u0101j\u0101mies par atbild\u0113m json dokumentu veid\u0101. <em>(Starpcitu, cik daudz pagaidu risin\u0101jumu n\u0101c\u0101s ievietot d\u0113\u013c ciklisk\u0101m atsauc\u0113m dokumentos?)<\/em>.<\/p>\n<p><\/p>\n<p>Es pied\u0101v\u0101ju izm\u0113\u0123in\u0101t v\u0113l vienu alternat\u012bvu pieeju \u2014 k\u0101p\u0113c gan neglab\u0101t visus datus lietojumprogrammas atmi\u0146\u0101, regul\u0101ri saglab\u0101jot tos nejau\u0161\u0101 kr\u0101tuv\u0113 (fails, att\u0101lin\u0101ta datub\u0101ze)?\u00a0<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Atmi\u0146a ir k\u013cuvusi l\u0113ta, un jebkuri iesp\u0113jamie dati vairumam mazo un vid\u0113jo projektu iek\u013caujas 1 GB atmi\u0146\u0101. <em>(Piem\u0113ram, mans iecien\u012bt\u0101kais m\u0101jas projekts \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/BudgetTracker\">finan\u0161u izsekot\u0101js<\/a><\/noindex>, kas veic ikdienas statistiku un manu izdevumu, bilances un dar\u012bjumu v\u0113sturi pusotru gadu, pat\u0113r\u0113 tikai 45 MB atmi\u0146as.)<\/em><\/p>\n<p><\/p>\n<p>Priek\u0161roc\u012bbas:<\/p>\n<p><\/p>\n<ul>\n<li>Piek\u013cuve datiem k\u013c\u016bst vienk\u0101r\u0161\u0101ka \u2014 nav j\u0101uztraucas par vaic\u0101jumiem, slinkaj\u0101m iel\u0101d\u0113m, ORM \u012bpatn\u012bb\u0101m, darbs notiek ar parastajiem C# objektiem;<\/li>\n<li>Nav probl\u0113mu, kas saist\u012btas ar piek\u013cuvi no da\u017e\u0101diem pavedieniem;<\/li>\n<li>\u013boti \u0101tri \u2014 nav t\u012bkla vaic\u0101jumu, nav koda transl\u0101cijas vaic\u0101jumu valod\u0101, nav nepiecie\u0161ama (de)serializ\u0101cija objektu;<\/li>\n<li>Ir pie\u0146emami glab\u0101t datus jebkur\u0101 veid\u0101 \u2014 gan XML disk\u0101, gan SQL Server, gan Azure Table Storage.<\/li>\n<\/ul>\n<p><\/p>\n<p>M\u012bnusi:<\/p>\n<p><\/p>\n<ul>\n<li>Pazaud\u0113ta horizont\u0101l\u0101 m\u0113rogo\u0161ana, l\u012bdz ar to nav iesp\u0113jams veikt zero downtime deployment;<\/li>\n<li>Ja lietojumprogramma avar\u0113 \u2014 iesp\u0113jams da\u013c\u0113ji zaud\u0113t datus. <em>(Bet m\u016bsu lietojumprogramma ta\u010du nekad neavar\u0113, vai ne?)<\/em><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">K\u0101 tas darbojas?<\/h2>\n<p><\/p>\n<p>Algoritms ir \u0161\u0101ds:<\/p>\n<p><\/p>\n<ul>\n<li>S\u0101kum\u0101 tiek izveidota savienojums ar datu kr\u0101tuvi, un notiek datu iel\u0101de;<\/li>\n<li>Tiek veidota objektu mode\u013cu strukt\u016bra, prim\u0101rie indeksi un attiec\u012bbu indeksi (1:1, 1:Daudz);<\/li>\n<li>Tiek izveidota abon\u0113\u0161ana uz objektu \u012bpa\u0161\u012bbu izmai\u0146\u0101m (INotifyPropertyChanged) un uz elementu pievieno\u0161anu vai dz\u0113\u0161anu kolekcij\u0101 (INotifyCollectionChanged);<\/li>\n<li>Kad abon\u0113\u0161ana tiek aktiviz\u0113ta, main\u012btais objekts tiek pievienots datu veikala ierakstu rindai;<\/li>\n<li>Periodiski (p\u0113c taimeri) fona pavedien\u0101 tiek saglab\u0101tas izmai\u0146as datu veikal\u0101;<\/li>\n<li>Izliekot no programmas, ar\u012b tiek saglab\u0101tas izmai\u0146as datu veikal\u0101.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"primer-koda\">Koda piem\u0113rs<\/h2>\n<p>\n<b class=\"spoiler_title\">Pievienojam nepiecie\u0161am\u0101s atkar\u012bbas<\/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\">Aprakst\u0101m datu modeli, kas tiks saglab\u0101ts datu veikal\u0101<\/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\">Tad ir objektu modelis:<\/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    \/\/ 1:Daudz attiec\u012bbu piem\u0113rs\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    \/\/ Pieejam\u012bba ar indeksu mekl\u0113\u0161anu\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\">Un visfinally pats datu piek\u013cuves klase - repozitorijs:<\/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; \/\/ Testiem, \u013cauj nesaglab\u0101t izmai\u0146as datu b\u0101z\u0113\n    \n        AddType((ParentEntity x) =&gt; new ParentModel(x));\n        AddType((ChildEntity x) =&gt; new ChildModel(x));\n    \n        \/\/ Ja tiek lietots Hangfire un nepiecie\u0161ams saglab\u0101t datu modeli Hangfire datu repozitorij\u0101\n        \/\/ this.RegisterHangfireScheme(); \n    \n        Initialize();\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>Izveidojam ObjectRepository instance:<\/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\">Ja projekt\u0101 tiks izmantots 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>Jauna objekta pievieno\u0161ana:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">var newParent = new ParentModel()\nrepository.Add(newParent);<\/code><\/pre>\n<p><\/p>\n<p>\u0160aj\u0101 izsaukum\u0101 objekts <strong>ParentModel<\/strong> tiek pievienots gan lok\u0101lajam ke\u0161atmi\u0146ai, gan ieraksta rindai datub\u0101z\u0113. T\u0101p\u0113c \u0161\u012b oper\u0101cija aiz\u0146em O(1), un ar \u0161o objektu var uzreiz str\u0101d\u0101t.<\/p>\n<p><\/p>\n<p>Piem\u0113ram, lai atrastu \u0161o objektu repozitorij\u0101 un p\u0101rliecin\u0101tos, ka atgrieztais objekts ir tas pats eksempl\u0101rs:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">var parents = repository.Set&lt;ParentModel&gt;();\nvar myParent = parents.Find(newParent.Id);\nAssert.IsTrue(ReferenceEquals(myParent, newParent));<\/code><\/pre>\n<p><\/p>\n<p>Kas notiek \u0161aj\u0101 gad\u012bjum\u0101? <em>Set&lt;ParentModel&gt;()<\/em> atgrie\u017e <em>TableDictionary&lt;ParentModel&gt;<\/em>, kas satur iek\u0161\u0101 <em>ConcurrentDictionary&lt;ParentModel, ParentModel&gt;<\/em> un pied\u0101v\u0101 papildu funkcionalit\u0101ti prim\u0101rajiem un sekund\u0101rajiem indeksi. Tas \u013cauj izmantot metodes mekl\u0113\u0161anai p\u0113c Id (vai citiem lietot\u0101ja indeksiem) bez visu objektu piln\u012bgas p\u0101rskat\u012b\u0161anas.<\/p>\n<p><\/p>\n<p>Pievienojot objektus <em>ObjectRepository<\/em> tiek pievienota paraksts uz to \u012bpa\u0161\u012bbu izmai\u0146\u0101m, t\u0101p\u0113c jebkura \u012bpa\u0161\u012bbu izmai\u0146a ar\u012b rezult\u0113 objekta pievieno\u0161an\u0101 ieraksta rindai.\u00a0<br \/>\nP\u0101rveidojot \u012bpa\u0161\u012bbas no \u0101rpuses, tas izskat\u0101s t\u0101pat k\u0101 str\u0101d\u0101jot ar POCO objektu:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">myParent.Children.First().Property = \"Atjaunot\u0101 v\u0113rt\u012bba\";<\/code><\/pre>\n<p><\/p>\n<p>Objektu var izdz\u0113st \u0161\u0101dos veidos:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">repository.Remove(myParent);\nrepository.RemoveRange(otherParents);\nrepository.Remove&lt;ParentModel&gt;(x =&gt; !x.Children.Any());<\/code><\/pre>\n<p><\/p>\n<p>\u0160aj\u0101 gad\u012bjum\u0101 notiek ar\u012b objekta pievieno\u0161ana izdz\u0113\u0161anas rindai.<\/p>\n<p><\/p>\n<h2 id=\"kak-rabotaet-sohranenie\">K\u0101 darbojas saglab\u0101\u0161ana?<\/h2>\n<p><\/p>\n<p><em>ObjectRepository<\/em> ja izsekojamo objektu izmai\u0146as (k\u0101 pievieno\u0161ana vai izdz\u0113\u0161ana, t\u0101pat k\u0101 \u012bpa\u0161\u012bbu izmai\u0146as) izsauc notikumu <em>ModelChanged<\/em>, uz kuru ir parakst\u012bjies <em>IStorage<\/em>. Realiz\u0101cijas <em>IStorage<\/em> notikuma ra\u0161an\u0101s gad\u012bjum\u0101 <em>ModelChanged<\/em> uzkr\u0101j izmai\u0146as 3 rind\u0101s \u2014 pievieno\u0161anai, atjaunin\u0101\u0161anai un izdz\u0113\u0161anai.<\/p>\n<p><\/p>\n<p>T\u0101pat realiz\u0101cijas <em>IStorage<\/em> savas inicializ\u0101cijas laik\u0101 izveido taimeri, kas ik p\u0113c 5 sekund\u0113m izsauc izmai\u0146u saglab\u0101\u0161anu.\u00a0<\/p>\n<p><\/p>\n<p><em>Turkl\u0101t past\u0101v API piespiedu saglab\u0101\u0161anas izsauk\u0161anai: <strong>ObjectRepository.Save()<\/strong>.<\/em><\/p>\n<p><\/p>\n<p>Pirms katras saglab\u0101\u0161anas vispirms notiek bezj\u0113dz\u012bgu oper\u0101ciju iz\u0146em\u0161ana no rind\u0101m (piem\u0113ram, notikumu dublik\u0101ti \u2014 kad objekts tika main\u012bts divreiz vai \u0101tra pievieno\u0161ana\/izdz\u0113\u0161ana), un tikai p\u0113c tam pati saglab\u0101\u0161ana.\u00a0<\/p>\n<p><\/p>\n<p><em>Visos gad\u012bjumos tiek saglab\u0101ts aktu\u0101lais objekts piln\u012bb\u0101, t\u0101p\u0113c var rasties situ\u0101cija, kad objekti tiek saglab\u0101ti cit\u0101 sec\u012bb\u0101, nek\u0101 main\u012bj\u0101s, taj\u0101 skait\u0101 var tikt saglab\u0101tas jaun\u0101kas objektu versijas, nek\u0101 br\u012bd\u012b, kad t\u0101s tika pievienotas rindai.<\/em><\/p>\n<p><\/p>\n<h2 id=\"chto-est-eschyo\">Kas v\u0113l ir?<\/h2>\n<p><\/p>\n<ul>\n<li>Visas bibliot\u0113kas balst\u0101s uz .NET Standard 2.0. To var izmantot jebkur\u0101 m\u016bsdienu .NET projekt\u0101.<\/li>\n<li>API ir pl\u016bsto\u0161s. Iek\u0161\u0113j\u0101s kolekcijas ir balst\u012btas uz <em>ConcurrentDictionary<\/em>, un notikumu apstr\u0101d\u0101t\u0101jiem ir vai nu blo\u0137\u0113\u0161ana, vai ar\u012b tas nav nepiecie\u0161ams.\u00a0<br \/>\nVien\u012bgais, kas j\u0101atceras \u2014 pirms lietojuma beig\u0161anas ir j\u0101v\u0113r\u0161as pie <em>ObjectRepository.Save();<\/em><\/li>\n<li>Patva\u013c\u012bgie indeksi (prasa unik\u0101lumu):<\/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\">Kas to lieto?<\/h2>\n<p><\/p>\n<p>Person\u012bgi es s\u0101ku izmantot \u0161o pieeju visos hobija projektos, jo tas ir \u0113rti un neprasa lielus izdevumus datu piek\u013cuves sl\u0101\u0146a rakst\u012b\u0161anai vai smagas infrastrukt\u016bras izveido\u0161anai. Man parasti pietiek ar datu glab\u0101\u0161anu litedb vai fail\u0101.\u00a0<\/p>\n<p><\/p>\n<p>Bet pag\u0101tn\u0113, kad ar komandu veidoj\u0101m tagad jau neeksist\u0113jo\u0161o startapu EscapeTeams (<em>dom\u0101ju, nu l\u016bk, nauda \u2014 bet n\u0113, atkal pieredze<\/em>) \u2014 izmantoj\u0101m Azure Table Storage datu glab\u0101\u0161anai.<\/p>\n<p><\/p>\n<h2 id=\"plany-na-buduschee\">N\u0101kotnes pl\u0101ni<\/h2>\n<p><\/p>\n<p>V\u0113l\u0113tos nov\u0113rst vienu no \u0161\u012b pieejas galvenajiem tr\u016bkumiem \u2014 horizont\u0101lo m\u0113rogo\u0161anu. Tam ir nepiecie\u0161amas vai nu izplat\u012btas transakcijas (sic!), vai j\u0101pie\u0146em ap\u0146\u0113m\u012bgs l\u0113mums, ka vien\u0101di dati no da\u017e\u0101d\u0101m instanc\u0113m nedr\u012bkst main\u012bties, vai ar\u012b \u013caut tiem main\u012bties p\u0113c principa \"kur\u0161 p\u0113d\u0113jais \u2014 tas ar\u012b pareizs\".<\/p>\n<p><\/p>\n<p>No tehnisk\u0101 viedok\u013ca redzu iesp\u0113jamu sekojo\u0161o sh\u0113mu:<\/p>\n<p><\/p>\n<ul>\n<li>Glab\u0101t nevis objektu modeli, bet gan EventLog un Snapshot<\/li>\n<li>Atrast citas instances (iek\u013caut vis\u0101s instance iestat\u012bjumos gala punktus? udp atkl\u0101\u0161ana? master\/slave?)<\/li>\n<li>Repliku veikt starp instanc\u0113m ar jebkuru no konsensa algoritmiem, piem\u0113ram, RAFT.<\/li>\n<\/ul>\n<p><\/p>\n<p>T\u0101pat past\u0101v v\u0113l viena probl\u0113ma, kas mani uztrauc \u2014 tas ir kask\u0101des dz\u0113\u0161ana, vai objektu, uz kuriem ir atsauces no citiem objektiem, dz\u0113\u0161anas gad\u012bjumu noteik\u0161ana.\u00a0<\/p>\n<p><\/p>\n<h2 id=\"ishodnyy-kod\">Atsl\u0113gas kods<\/h2>\n<p><\/p>\n<p>Ja j\u016bs esat izlas\u012bjis l\u012bdz \u0161im \u2014 tad t\u0101l\u0101k paliek tikai las\u012bt kodu, to var atrast GitHub:<br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/ObjectRepository\">https:\/\/github.com\/DiverOfDark\/ObjectRepository<\/a><\/noindex><\/p>\n<p>Avots: <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.5 - 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\/lv\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.5\" \/>\n\t\t<meta property=\"og:locale\" content=\"lv_LV\" \/>\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\/lv\/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 .NET iek\u0161\u0113j\u0101 glab\u0101\u0161anas re\u017e\u012bma paraugs j\u016bsu m\u0101jas projektiem | ProHoster","description":"K\u0101p\u0113c glab\u0101t visus datus atmi\u0146\u0101? Datu glab\u0101\u0161anai vietn\u0113 vai aizmugur\u0113 daudzu sapr\u0101t\u012bgu cilv\u0113ku pirmais izv\u0113le b\u016btu SQL datub\u0101ze.","canonical_url":"https:\/\/prohoster.info\/lv\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"lv_LV","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\/lv\/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\/lv\/wp-json\/wp\/v2\/posts\/33839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/comments?post=33839"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/posts\/33839\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/media?parent=33839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/categories?post=33839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/tags?post=33839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}