{"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\/et\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","title":{"rendered":"ObjectRepository \u2014 .NET m\u00e4luandmehoidja mudel teie koduste projektide jaoks","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2 id=\"zachem-hranit-vse-dannye-v-pamyati\">Miks hoida k\u00f5iki andmeid m\u00e4lus?<\/h2>\n<p><\/p>\n<p>Veebisaidi v\u00f5i serveri andmete salvestamiseks valib enamik m\u00f5istlikke inimesi k\u00f5igepealt SQL andmebaasi.\u00a0<\/p>\n<p><\/p>\n<p>Kuid m\u00f5nikord tuleb m\u00f5te, et andmemudel ei sobi SQL-iga: n\u00e4iteks, kui ehitada otsingut v\u00f5i sotsiaalset graafi, on vaja otsida keeruliste seoste kaudu objektide vahel.\u00a0<\/p>\n<p><\/p>\n<p><strong>Halvimal juhul juhtub, et t\u00f6\u00f6tate meeskonnas ja kolleeg ei oska ehitada kiireid p\u00e4ringuid. Kui palju aega olete kulutanud N+1 probleemide lahendamiseks ja t\u00e4iendavate indeksite loomiseks, et SELECT pealdival t\u00f6\u00f6le hakkaks m\u00f5istliku ajaga?<\/strong><\/p>\n<p><\/p>\n<p>Teine populaarne l\u00e4henemine on NoSQL. M\u00f5ned aastad tagasi oli selle teema \u00fcmber suur m\u00fcra \u2014 igaks juhuks k\u00e4ivitati MongoDB ja r\u00f5\u00f5mustati JSON-dokumentide vastuste \u00fcle. <em>(Muide, kui palju tugitooteid tuli ts\u00fckliliste viidete t\u00f5ttu dokumentidesse lisada?)<\/em>.<\/p>\n<p><\/p>\n<p>Pakun proovida veel \u00fcht alternatiivset viisi \u2014 miks mitte hoida k\u00f5iki andmeid rakenduse m\u00e4lus, perioodiliselt salvestades need juhuslikku hoidlisse (fail, kaugandmebaas)?\u00a0<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>M\u00e4lu on muutunud odavaks ja enamik v\u00e4ikeste ja keskmiste projektide andmeid mahub 1 GB m\u00e4llu. <em>(N\u00e4iteks, minu lemmik koduprojekt \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/BudgetTracker\">finantsij\u00e4lgija<\/a><\/noindex>, mis hoiab p\u00e4evast statistikat ja ajalugu minu kulutuste, saldode ja tehingute kohta poolteise aasta jooksul, tarbib vaid 45 MB m\u00e4lu.)<\/em><\/p>\n<p><\/p>\n<p>Plussid:<\/p>\n<p><\/p>\n<ul>\n<li>Andmetele juurdep\u00e4\u00e4s on lihtsam \u2014 ei ole vaja muretseda p\u00e4ringute, laiskade laadimiste, ORM-i omaduste \u00fcle, t\u00f6\u00f6 toimub tavaliste C# objektidega;<\/li>\n<li>Ei ole probleeme, mis on seotud juurdep\u00e4\u00e4suga erinevatest niitidest;<\/li>\n<li>V\u00e4ga kiire \u2014 ei mingeid v\u00f5rgup\u00e4ringuid, puudub koodi t\u00f5lkimine p\u00e4ringukeelde, ei ole vaja (de)serialiseerida objekte;<\/li>\n<li>Lubatud on hoida andmeid igas vormis \u2014 olgu need XML diskil, SQL Serveris v\u00f5i Azure Table Storage'is.<\/li>\n<\/ul>\n<p><\/p>\n<p>Miinused:<\/p>\n<p><\/p>\n<ul>\n<li>Kaduda v\u00f5ib horisontaalne skaleeritavus ja seega ei saa teha nullkatkestust juurutust;<\/li>\n<li>Kui rakendus kukub, v\u00f5ib andmeid osaliselt kaduda. <em>(Aga meie rakendus ju ei kuku kunagi, eks?)<\/em><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Kuidas see t\u00f6\u00f6tab?<\/h2>\n<p><\/p>\n<p>Algoritm on j\u00e4rgmine:<\/p>\n<p><\/p>\n<ul>\n<li>Alguses luuakse \u00fchendus andmehoidla, ja toimub andmete laadimine;<\/li>\n<li>Ehitatakse objekti mudel, esmased indeksid ja seoseindeksid (1:1, 1:palju);<\/li>\n<li>Loodakse tellimus objektide omaduste (INotifyPropertyChanged) ja elementide lisamise v\u00f5i eemaldamise kohta kogus (INotifyCollectionChanged);<\/li>\n<li>Tellimuse aktiveerimisel lisatakse muudetud objekt andmehoidla kirjutamise j\u00e4rjekorda;<\/li>\n<li>Perioodiliselt (ajastiga) salvestatakse taustprotsessis muudatused andmehoidlas;<\/li>\n<li>Rakendusest lahkumisel salvestatakse samuti muudatused andmehoidlas.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"primer-koda\">Koodin\u00e4ide<\/h2>\n<p>\n<b class=\"spoiler_title\">Lisame vajalikud s\u00f5ltuvused<\/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\">Kirjeldame andmemudelit, mis salvestatakse andmehoidlas<\/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\">Seej\u00e4rel objekti mudel:<\/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    \/\/ N\u00e4ide seosest 1:Many\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    \/\/ Juhtimine indeksi p\u00f5hjal\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\">Ja l\u00f5puks, klass-repositorium andmete ligip\u00e4\u00e4suks:<\/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; \/\/ Testimiseks, v\u00f5imaldab mitte salvestada muudatusi andmebaasi\n    \n        AddType((ParentEntity x) =&gt; new ParentModel(x));\n        AddType((ChildEntity x) =&gt; new ChildModel(x));\n    \n        \/\/ Kui kasutatakse Hangfire'i ja on vaja salvestada andmemudelit Hangfire'i jaoks ObjectRepository's\n        \/\/ this.RegisterHangfireScheme();  \n    \n        Initialize();\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>Loome ObjectRepository eksemplari:<\/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\">Kui projektis kasutatakse HangFire'i<\/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>Uue objekti lisamine:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">var newParent = new ParentModel()\nrepository.Add(newParent);<\/code><\/pre>\n<p><\/p>\n<p>Selle kutsumise korral objekt <strong>ParentModel<\/strong> lisatakse nii kohaliku vahem\u00e4lu kui ka kirjutamise j\u00e4rjekorda andmebaasi. Seet\u00f5ttu v\u00f5tab see operatsioon aega O(1) ja selle objekti kallal saab kohe t\u00f6\u00f6tada.<\/p>\n<p><\/p>\n<p>N\u00e4iteks, et leida see objekt repository's ja kinnitada, et tagastatud objekt on sama eksemplar:<\/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>Mida sel ajal toimub? <em>Set()<\/em> toob tagasi <em>TableDictionary<\/em>, mis sisaldab endas <em>ConcurrentDictionary<\/em> ja pakub lisafunktsioone esmase ja teisej\u00e4rgulise indekseerimise jaoks. See v\u00f5imaldab otsimise meetodeid Id (v\u00f5i muude suvaliste kasutajaindeksite) alusel ilma k\u00f5igi objektide t\u00e4ieliku l\u00e4bivaatamiseta.<\/p>\n<p><\/p>\n<p>Objektide lisamisel <em>ObjectRepository<\/em> lisatakse tellimus nende omaduste muutmise jaoks, seega toob iga omaduste muutmine kaasa selle objekti lisamise kirjutamise j\u00e4rjekorda.\u00a0<br \/>\nOmaduste v\u00e4rskendamine v\u00e4ljastpoolt n\u00e4eb v\u00e4lja sarnaselt POCO-objektiga t\u00f6\u00f6tamisega:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">myParent.Children.First().Property = \"Uuendatud v\u00e4\u00e4rtus\";<\/code><\/pre>\n<p><\/p>\n<p>Objekti saab eemaldada j\u00e4rgmistel viisidel:<\/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>Sellega toimub ka objekti lisamine kustutamise j\u00e4rjekorda.<\/p>\n<p><\/p>\n<h2 id=\"kak-rabotaet-sohranenie\">Kuidas salvestamine t\u00f6\u00f6tab?<\/h2>\n<p><\/p>\n<p><em>ObjectRepository<\/em> kui j\u00e4lgitavate objektide muutmine (kas lisamine, eemaldamine v\u00f5i omaduste muutmine) kutsub esile s\u00fcndmuse <em>ModelChanged<\/em>, millele on tellinud <em>IStorage<\/em>. Teostused <em>IStorage<\/em> selle s\u00fcndmuse toimumisel <em>ModelChanged<\/em> koguvad muudatused 3 j\u00e4rjekorda \u2013 lisamine, uuendamine ja eemaldamine.<\/p>\n<p><\/p>\n<p>Samuti loovad teostused algatamisel taimeri, mis iga 5 sekundi j\u00e4rel kutsub esile muudatuste salvestamise. <em>IStorage<\/em> Lisaks on olemas API sundsalvestamiseks:\u00a0<\/p>\n<p><\/p>\n<p><em>ObjectRepository.Save() <strong>Enne iga salvestamist eemaldatakse k\u00f5igepealt j\u00e4rjekordadest m\u00f5ttetud operatsioonid (n\u00e4iteks s\u00fcndmuste dubleerimine \u2014 kui objekti muudeti kaks korda v\u00f5i objekti kiire lisamine\/eemaldamine) ja alles seej\u00e4rel toimub salvestamine.<\/strong>.<\/em><\/p>\n<p><\/p>\n<p>K\u00f5igis juhtudel salvestatakse aktuaalne objekt t\u00e4ielikult, seega v\u00f5ib juhtuda olukord, kus objekte salvestatakse teises j\u00e4rjestuses kui need muutusid, sealhulgas v\u00f5ivad salvestuda uuemad versioonid objektidest kui need lisati j\u00e4rjekorda.\u00a0<\/p>\n<p><\/p>\n<p><em>Mis veel on olemas?<\/em><\/p>\n<p><\/p>\n<h2 id=\"chto-est-eschyo\">K\u00f5ik raamatukogud p\u00f5hinevad .NET Standard 2.0-l. Saab kasutada mis tahes kaasaegses .NET projektis.<\/h2>\n<p><\/p>\n<ul>\n<li>K\u00f5ik raamatukogud p\u00f5hinevad .NET Standard 2.0-l. Saab kasutada mis tahes kaasaegses .NET projektis.<\/li>\n<li>API on veelkasutatav. Sised kolektsioonid on rakendatud <em>ConcurrentDictionary<\/em>, s\u00fcndmuste k\u00e4sitlejad kas omavad lukustusi v\u00f5i ei vaja neid.\u00a0<br \/>\nAinus, mille \u00fcle tasub meeles pidada, on see, et rakenduse l\u00f5petamisel tuleks kutsuda <em>ObjectRepository.Save();<\/em><\/li>\n<li>Meelevaldne indeks (n\u00f5uab unikaalsust):<\/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\">Kes seda kasutab?<\/h2>\n<p><\/p>\n<p>Isiklikult hakkasin seda l\u00e4henemist kasutama k\u00f5igis oma hobi projektides, sest see on mugav ja ei n\u00f5ua suurt vaeva andmejuurdep\u00e4\u00e4su kihi kirjutamisel v\u00f5i raske infrastruktuuri k\u00e4ivitamisel. \u00dcldiselt piisab mulle andmete salvestamisest litedb-s v\u00f5i failis.\u00a0<\/p>\n<p><\/p>\n<p>Kuid minevikus, kui tegime meeskonnaga praegu kustutatud idufirma EscapeTeams (<em>m\u00f5tlesin, et n\u00fc\u00fcd on raha \u2014 aga ei, j\u00e4lle kogemus<\/em>) \u2014 kasutasime andmete salvestamiseks Azure Table Storage'i.<\/p>\n<p><\/p>\n<h2 id=\"plany-na-buduschee\">Tulevikuplaanid<\/h2>\n<p><\/p>\n<p>Sooviks parandada selle l\u00e4henemise \u00fchte peamist miinust \u2014 horisontaalset skaleerimist. Selleks on vaja kas jaotatud tehinguid (sic!), v\u00f5i teha kindel otsus, et samad andmed erinevates instantsides ei peaks muutuma, v\u00f5i muutugu need p\u00f5him\u00f5tte j\u00e4rgi \u201ekeda viimane, see \u00f5ige\u201c.<\/p>\n<p><\/p>\n<p>Tehnilisest vaatepunktist n\u00e4en v\u00f5imalikku j\u00e4rgmist skeemi:<\/p>\n<p><\/p>\n<ul>\n<li>Salvestada objektide mudeli asemel EventLog ja Snapshot<\/li>\n<li>Leida teised instantsid (lisada seadistustesse k\u00f5igi instantside l\u00f5pp-punktid? udp avastamine? master\/slave?)<\/li>\n<li>Replitseerida instantside vahel EventLog'i l\u00e4bi m\u00f5ne konsensuse algoritmi, n\u00e4iteks RAFT.<\/li>\n<\/ul>\n<p><\/p>\n<p>Samuti on olemas veel \u00fcks probleem, mis mind h\u00e4irib \u2014 see on kaskaadne kustutamine v\u00f5i avastamine olukordadest, kus objektide kustutamist, millele viidatakse teistest objektidest.\u00a0<\/p>\n<p><\/p>\n<h2 id=\"ishodnyy-kod\">Allika kood<\/h2>\n<p><\/p>\n<p>Kui lugesite siia, siis edasi j\u00e4\u00e4b vaid koodi lugemine, seda saab leida GitHubist:<br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/ObjectRepository\">https:\/\/github.com\/DiverOfDark\/ObjectRepository<\/a><\/noindex><\/p>\n<p>Allikas: <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.1.1 - 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\/et\/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.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\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\/et\/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 m\u00e4lurepositooriumi muster teie koduprojektide jaoks | ProHoster","description":"Miks salvestada k\u00f5ik andmed m\u00e4llu? Veebisaidi v\u00f5i tagapinna andmete salvestamiseks valivad enamik m\u00f5istlikke inimesi esimesena SQL andmebaasi.","canonical_url":"https:\/\/prohoster.info\/et\/blog\/news\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","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\/et\/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\/et\/wp-json\/wp\/v2\/posts\/33839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=33839"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/33839\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=33839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=33839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=33839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}