{"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\/novosti-interneta\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","title":{"rendered":"ObjectRepository \u2014 .NET m\u00e4lureposiitoori mudel teie isiklike projektide jaoks","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2 id=\"zachem-hranit-vse-dannye-v-pamyati\">Miks hoida kogu teavet m\u00e4lus?<\/h2>\n<p><\/p>\n<p>Veebisaidi v\u00f5i taustas\u00fcsteemi andmete salvestamisel valivad enamik m\u00f5istlikke inimesi esmalt SQL andmebaasi.\u00a0<\/p>\n<p><\/p>\n<p>Kuid m\u00f5nikord tekib m\u00f5te, et andmemudel ei sobi SQL-iga: n\u00e4iteks otsingu v\u00f5i sotsiaalsete graafikute koostamisel on vajalik keeruline objekti vaheliste seoste otsimine.\u00a0<\/p>\n<p><\/p>\n<p><strong>Halvim on see, kui t\u00f6\u00f6tate meeskonnas ja kolleeg ei oska luua kiireid p\u00e4ringuid. Kui palju aega olete kulutanud N+1 probleemide lahendamisele ja t\u00e4iendavate indeksite loomisele, et SELECT peaeesm\u00e4rgil t\u00f6\u00f6taks m\u00f5istliku ajaga?<\/strong><\/p>\n<p><\/p>\n<p>Teine populaarne l\u00e4henemine on NoSQL. M\u00f5ni aasta tagasi oli selle teema \u00fcmber suur m\u00fcra \u2014 iga sobiva juhtumi jaoks k\u00e4ivitasime MongoDB ja nautisime vastuseid JSON-dokumentidena. <em>(Muide, kui palju kompromisse tuli dokumentides ts\u00fckliliste linkide t\u00f5ttu teha?)<\/em>.<\/p>\n<p><\/p>\n<p>Pakun proovima veel \u00fchte alternatiivset viisi \u2014 miks mitte hoida k\u00f5iki andmeid rakenduse m\u00e4lus, salvestades neid perioodiliselt mis tahes salvestusse (fail, kaugandmebaas)?\u00a0<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>M\u00e4lu on saanud odavaks ning 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\">rahanduse j\u00e4lgija<\/a><\/noindex>, mis hoiab igap\u00e4evast statistikat ja minu kulutuste, saldod ja tehingute ajalugu aasta ja kuu jooksul, vajab vaid 45 MB m\u00e4lu.)<\/em><\/p>\n<p><\/p>\n<p>Plussid:<\/p>\n<p><\/p>\n<ul>\n<li>Andmetele p\u00e4\u00e4semine on lihtsam \u2014 ei pea muretsema p\u00e4ringute, laiskade laadimise, ORM-iga seotud erip\u00e4rade p\u00e4rast, t\u00f6\u00f6 toimub tavap\u00e4raste C# objektidega;<\/li>\n<li>Ei ole probleeme erinevatest l\u00f5ngadest juurdep\u00e4\u00e4suga;<\/li>\n<li>V\u00e4ga kiire \u2014 pole v\u00f5rgu p\u00e4ringuid, puudub koodi t\u00f5lkimine p\u00e4ringute keelde, ei ole vaja (de)serialiseerida objekte;<\/li>\n<li>Andmeid v\u00f5ib hoida mis tahes vormis \u2014 kas siis XML-is kettal, 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>Kadunud horisontaalne skaaleerimine, mis t\u00e4hendab, et ei saa teostada null-sisaldusega juurutamist;<\/li>\n<li>Kui rakendus langeb, on andmed osaliselt kadunud. <em>(Aga meie rakendus ei krahhi 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>Algr\u00fctm on j\u00e4rgmine:<\/p>\n<p><\/p>\n<ul>\n<li>Alustamisel luuakse \u00fchendus andmehoidla ning laaditakse andmed;<\/li>\n<li>Ehitatakse objekti mudel, esmased indeksid ja seose indeksid (1:1, 1:Many);<\/li>\n<li>Loodakse tellimus objekti omaduste muutuste (INotifyPropertyChanged) ning elementide lisamise v\u00f5i eemaldamise kohta kogus (INotifyCollectionChanged);<\/li>\n<li>Tellimuse aktiveerimisel \u2014 muudetud objekt lisatakse andmehoidlasse salvestamise j\u00e4rjekorda;<\/li>\n<li>Perioodiliselt (ajastaja kaudu) taustaprotsessis salvestatakse muudatused andmehoidlasse;<\/li>\n<li>Rakendusest v\u00e4ljumisel salvestatakse samuti muudatused andmehoidlasse.<\/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 andmehoidlasse<\/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:Palju\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    \/\/ Otsinguhindade abil\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-repositoorium andmete juurde p\u00e4\u00e4semiseks:<\/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 Hangfire'i kasutatakse ja on vajalik salvestada andmemudelit Hangfire'i objektirepositooriumis\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>Sel hetkel lisatakse objekt <strong>ParentModel<\/strong> nii kohalikku vahem\u00e4lusse kui ka kirjutamisj\u00e4rjekorda andmebaasis. Seet\u00f5ttu v\u00f5tab see operatsioon O(1) aega ja seda objekti saab kohe kasutada.<\/p>\n<p><\/p>\n<p>N\u00e4iteks, et leida see objekt repositooriumist ja veenduda, 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>Mis sel hetkel juhtub? <em>Set()<\/em> tagastab <em>TableDictionary<\/em>, mis sisaldab endas <em>ConcurrentDictionary<\/em> ja pakub t\u00e4iendavaid funktsioone peamiste ja teiseste indeksite jaoks. See v\u00f5imaldab meetodeid otsimiseks ID j\u00e4rgi (v\u00f5i muude juhuslike kasutaja indeksite j\u00e4rgi) ilma k\u00f5igi objektide t\u00e4ieliku l\u00e4bivaatamiseta.<\/p>\n<p><\/p>\n<p>Objektide lisamisel <em>ObjectRepository<\/em> lisatakse tellimus nende omaduste muutmisele, seega toob iga omaduste muutumine kaasa ka selle objekti lisamise kirjutamisj\u00e4rjekorda.\u00a0<br \/>\nOmandite v\u00e4ljastpoolt v\u00e4rskendamine toimub nagu ka POCO-objektidega t\u00f6\u00f6tamine:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">myParent.Children.First().Property = \"V\u00e4rskendatud 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>Samuti toimub objekti lisamine eemaldamise 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\u00e4lgitud objekte muudetakse (n\u00e4iteks lisamine, eemaldamine v\u00f5i omaduste muutmine) kutsub see esile s\u00fcndmuse <em>ModelChanged<\/em>, millele on tellinud <em>IStorage<\/em>. Teostused <em>IStorage<\/em> s\u00fcndmuse tekkimisel <em>ModelChanged<\/em> koguvad muudatused 3 j\u00e4rjekorda \u2014 lisamine, v\u00e4rskendamine ja eemaldamine.<\/p>\n<p><\/p>\n<p>Samuti teostused <em>IStorage<\/em> Algoritm k\u00e4ivitamisel luuakse taimer, mis kutsub iga 5 sekundi j\u00e4rel esile muudatuste salvestamise.\u00a0<\/p>\n<p><\/p>\n<p><em>Lisaks on olemas API sundsalvestamise jaoks: <strong>ObjectRepository.Save()<\/strong>.<\/em><\/p>\n<p><\/p>\n<p>Iga salvestamise eel eemaldatakse j\u00e4rjekordadest m\u00f5ttetud toimingud (n\u00e4iteks s\u00fcndmuste duplikaadid \u2014 kui objekt muutus kaks korda v\u00f5i objekti kiire lisamine\/eemaldamine), ja alles siis toimub salvestamine.\u00a0<\/p>\n<p><\/p>\n<p><em>Igal juhul salvestatakse kogu kehtiv objekt, mist\u00f5ttu v\u00f5ib juhtuda, et objekte salvestatakse erinevas j\u00e4rjekorras kui need muutusid, sealhulgas v\u00f5ivad salvestuda uuemad versioonid objektidest kui need j\u00e4rjekorda lisamisel.<\/em><\/p>\n<p><\/p>\n<h2 id=\"chto-est-eschyo\">Mis on veel?<\/h2>\n<p><\/p>\n<ul>\n<li>K\u00f5ik raamatukogud p\u00f5hinevad .NET Standard 2.0-l. Saate kasutada igas kaasaegses .NET projektis.<\/li>\n<li>API on l\u00f5imivaba. Sisemist kollektsiooni on rakendatud <em>ConcurrentDictionary<\/em>, s\u00fcndmuste t\u00f6\u00f6tlejate juures on kas lukud v\u00f5i ei ole neid vaja.\u00a0<br \/>\nAinus, mida tuleks meeles pidada \u2014 rakenduse l\u00f5petamisel kutsuda esile <em>ObjectRepository.Save();<\/em><\/li>\n<li>Mugavad indeksid (n\u00f5uavad 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 hakkan ma seda l\u00e4henemist k\u00f5ikides oma hobi projektides kasutama, kuna see on mugav ja ei n\u00f5ua suuri kulutusi andmete juurdep\u00e4\u00e4sutasandi kirjutamiseks v\u00f5i keeruka infrastruktuuri seadistamiseks. Minu jaoks piisab tavaliselt andmete hoidmisest litedb v\u00f5i failis.\u00a0<\/p>\n<p><\/p>\n<p>Aga varem, kui koos meeskonnaga tegime n\u00fc\u00fcdseks kadunud startuppi EscapeTeams (<em>m\u00f5tlesin, et n\u00fc\u00fcd on raha \u2014 aga ei, j\u00e4lle kogemus<\/em>) \u2014 kasutasime andmete hoidmiseks Azure Table Storage.<\/p>\n<p><\/p>\n<h2 id=\"plany-na-buduschee\">Tulevikuplaanid<\/h2>\n<p><\/p>\n<p>Soovitakse parandada \u00fche peamise selle l\u00e4henemise miinusena \u2014 horisontaalne skaleerimine. Selleks on vajalikud kas jaotatud tehingud (sic!), v\u00f5i tuleks vastu v\u00f5tta otsus, et samad andmed erinevatesse instantsidesse ei tohiks muutuda, v\u00f5i lasta need muutuda p\u00f5him\u00f5ttel \u00abkelle viimane \u2014 see \u00f5ige\u00bb.<\/p>\n<p><\/p>\n<p>Tehnilisest vaatepunktist n\u00e4en ma j\u00e4rgmise skeemi v\u00f5imalikuna:<\/p>\n<p><\/p>\n<ul>\n<li>Hoidke objekti mudeli asemel EventLog ja Snapshot<\/li>\n<li>Leida teised instantsid (kas lisada k\u00f5ikide instantside l\u00f5pp-punktide seadistustesse? udp avastamine? master\/slave?)<\/li>\n<li>Replitseerige EventLog instantside vahel mis tahes konsensuse algoritmiga, n\u00e4iteks RAFT.<\/li>\n<\/ul>\n<p><\/p>\n<p>On veel mures, mis mind h\u00e4irivad \u2014 see on kaskaadsete kustutamiste v\u00f5i juhtumite tuvastamine, kus objektid, millele viidatakse, on kustutatud teistest objektidest.\u00a0<\/p>\n<p><\/p>\n<h2 id=\"ishodnyy-kod\">Allikasood<\/h2>\n<p><\/p>\n<p>Kui olete siiani lugenud \u2014 j\u00e4\u00e4b \u00fcle ainult koodi lugemine, mille leiate 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-novosti-interneta"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - 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. \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. \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,\" \/>\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\/novosti-interneta\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\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. \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. \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,\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/et\/blog\/novosti-interneta\/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 in-memory repository pattern teie koduprojektide jaoks | ProHoster","description":"Miks hoida k\u00f5iki andmeid m\u00e4lus? Veebisaidi v\u00f5i tahkete andmete salvestamiseks valib enamus m\u00f5istlikest inimestest SQL andmebaasi. Kuid m\u00f5nikord tekib m\u00f5te, et andmemudel ei sobi SQL-iga: n\u00e4iteks otsingu v\u00f5i sotsiaalsete graafikute loomisel on vajalik komplekssete suhete kaudu otsimine objektide vahel. Halvim on olukord, kui t\u00f6\u00f6tate meeskonnas.","canonical_url":"https:\/\/prohoster.info\/et\/blog\/novosti-interneta\/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. \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. \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,","og:url":"https:\/\/prohoster.info\/et\/blog\/novosti-interneta\/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"},"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}]}}