{"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\/de\/blog\/novosti-interneta\/objectrepository-net-in-memory-repository-pattern-dlya-vashih-domashnih-proektov","title":{"rendered":"ObjectRepository \u2014 .NET In-Memory-Repository-Muster f\u00fcr Ihre Heimprojekte","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2 id=\"zachem-hranit-vse-dannye-v-pamyati\">Warum alle Daten im Speicher aufbewahren?<\/h2>\n<p><\/p>\n<p>F\u00fcr die Speicherung von Website- oder Backend-Daten w\u00fcrden die meisten vern\u00fcnftigen Menschen zun\u00e4chst eine SQL-Datenbank w\u00e4hlen.\u00a0<\/p>\n<p><\/p>\n<p>Aber manchmal kommt der Gedanke auf, dass das Datenmodell nicht f\u00fcr SQL geeignet ist: Zum Beispiel, wenn es darum geht, eine Suche oder ein soziales Netzwerk zu erstellen, ben\u00f6tigt man eine Suche nach komplexen Beziehungen zwischen Objekten.\u00a0<\/p>\n<p><\/p>\n<p><strong>Am schlimmsten ist es, wenn man im Team arbeitet und ein Kollege keine schnellen Abfragen erstellen kann. Wie viel Zeit haben Sie damit verbracht, die Probleme N+1 zu l\u00f6sen und zus\u00e4tzliche Indizes zu erstellen, damit der SELECT-Befehl auf der Hauptseite in angemessener Zeit bearbeitet wird?<\/strong><\/p>\n<p><\/p>\n<p>Ein weiterer beliebter Ansatz ist NoSQL. Vor einigen Jahren gab es viel Hype um dieses Thema \u2013 bei jeder Gelegenheit wurde MongoDB eingerichtet, und alle freuten sich \u00fcber die Antworten in Form von JSON-Dokumenten. <em>(\u00dcbrigens, wie viele Workarounds mussten wegen zyklischer Verweise in den Dokumenten eingesetzt werden?)<\/em>.<\/p>\n<p><\/p>\n<p>Ich schlage vor, einen weiteren alternativen Ansatz auszuprobieren \u2013 warum nicht alle Daten im Anwendungs-Speicher aufbewahren und sie regelm\u00e4\u00dfig in ein beliebiges Repository (Datei, Remote-Datenbank) speichern?\u00a0<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Speicher ist billig geworden, und alle erforderlichen Daten der meisten kleinen und mittelst\u00e4ndischen Projekte passen in 1 GB RAM. <em>(Zum Beispiel, mein Lieblingsprojekt zu Hause \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/BudgetTracker\">ein Finanz-Tracker<\/a><\/noindex>, der t\u00e4gliche Statistiken und eine Historie meiner Ausgaben, Salden und Transaktionen \u00fcber anderthalb Jahre hinweg erfasst, ben\u00f6tigt nur 45 MB RAM.)<\/em><\/p>\n<p><\/p>\n<p>Vorteile:<\/p>\n<p><\/p>\n<ul>\n<li>Der Zugriff auf Daten wird einfacher \u2014 man muss sich nicht um Abfragen, verz\u00f6gertes Laden oder die Besonderheiten von ORM k\u00fcmmern, die Arbeit erfolgt mit normalen C#-Objekten;<\/li>\n<li>Es gibt keine Probleme mit dem Zugriff aus verschiedenen Threads;<\/li>\n<li>Sehr schnell \u2014 keine Netzwerkabfragen, keine \u00dcbersetzung des Codes in die Abfragesprache, keine (De-)Serialisierung von Objekten erforderlich;<\/li>\n<li>Es ist erlaubt, Daten in beliebiger Form zu speichern \u2014 sei es XML auf der Festplatte, SQL Server oder Azure Table Storage.<\/li>\n<\/ul>\n<p><\/p>\n<p>Nachteile:<\/p>\n<p><\/p>\n<ul>\n<li>Horizontales Skalieren geht verloren, und folglich ist ein Zero Downtime Deployment nicht m\u00f6glich;<\/li>\n<li>Wenn die Anwendung ausf\u00e4llt \u2014 k\u00f6nnen Daten teilweise verloren gehen. <em>(Aber unsere Anwendung st\u00fcrzt doch niemals ab, oder?)<\/em><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Wie funktioniert das?<\/h2>\n<p><\/p>\n<p>Das Verfahren ist wie folgt:<\/p>\n<p><\/p>\n<ul>\n<li>Beim Start wird eine Verbindung zum Datenspeicher hergestellt und die Daten werden geladen;<\/li>\n<li>Es wird ein objektmodell gebaut, prim\u00e4re Indizes und Beziehungsindizes (1:1, 1:n);<\/li>\n<li>Ein Abonnement f\u00fcr \u00c4nderungen an Objekteigenschaften (INotifyPropertyChanged) sowie f\u00fcr das Hinzuf\u00fcgen oder Entfernen von Elementen in einer Sammlung (INotifyCollectionChanged) wird erstellt.<\/li>\n<li>Wenn das Abonnement ausgel\u00f6st wird, wird das ge\u00e4nderte Objekt in die Warteschlange zum Speichern in der Datenablage hinzugef\u00fcgt.<\/li>\n<li>\u00c4nderungen werden regelm\u00e4\u00dfig (im Hintergrund-Thread \u00fcber einen Timer) in der Datenablage gespeichert.<\/li>\n<li>\u00c4nderungen werden auch beim Verlassen der Anwendung in der Datenablage gespeichert.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"primer-koda\">Beispielcode<\/h2>\n<p>\n<b class=\"spoiler_title\">F\u00fcgen Sie die erforderlichen Abh\u00e4ngigkeiten hinzu.<\/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\">Beschreiben Sie das Datenmodell, das in der Datenablage gespeichert werden soll.<\/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\">Dann das Objektmodell:<\/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    \/\/ Beispiel f\u00fcr eine 1:Viele Beziehung\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    \/\/ Zugriff mit Indexsuche\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\">Und schlie\u00dflich die Repository-Klasse f\u00fcr den Datenzugriff:<\/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; \/\/ F\u00fcr Tests, erm\u00f6glicht es, keine \u00c4nderungen in der Datenbank zu speichern\n    \n        AddType((ParentEntity x) =&gt; new ParentModel(x));\n        AddType((ChildEntity x) =&gt; new ChildModel(x));\n    \n        \/\/ Wenn Hangfire verwendet wird und das Datenmodell f\u00fcr Hangfire im ObjectRepository gespeichert werden muss\n        \/\/ this.RegisterHangfireScheme();\n    \n        Initialize();\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>Erstellen eines Instanz von 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\">Wenn im Projekt HangFire verwendet wird<\/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>Einf\u00fcgen eines neuen Objekts:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">var newParent = new ParentModel()\nrepository.Add(newParent);<\/code><\/pre>\n<p><\/p>\n<p>Bei diesem Aufruf wird das Objekt <strong>ParentModel<\/strong> wird sowohl im lokalen Cache als auch in die Warteschlange f\u00fcr die Datenbank geschrieben. Daher hat dieser Vorgang O(1) und dieses Objekt kann sofort verwendet werden.<\/p>\n<p><\/p>\n<p>Um beispielsweise dieses Objekt im Repository zu finden und sicherzustellen, dass das zur\u00fcckgegebene Objekt dasselbe Exemplar ist:<\/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>Was passiert dabei? <em>Set&lt;ParentModel&gt;()<\/em> gibt er <em>TableDictionary&lt;ParentModel&gt;<\/em>, der enth\u00e4lt <em>ConcurrentDictionary&lt;ParentModel, ParentModel&gt;<\/em> und bietet zus\u00e4tzliche Funktionalit\u00e4ten f\u00fcr prim\u00e4re und sekund\u00e4re Indizes. Dadurch stehen Methoden zur Verf\u00fcgung, um nach Id (oder anderen beliebigen benutzerdefinierten Indizes) zu suchen, ohne alle Objekte vollst\u00e4ndig durchzuscannen.<\/p>\n<p><\/p>\n<p>Beim Hinzuf\u00fcgen von Objekten zu <em>ObjectRepository<\/em> wird ein Abonnement zur \u00c4nderung ihrer Eigenschaften hinzugef\u00fcgt, sodass jede \u00c4nderung der Eigenschaften auch zur Aufnahme dieses Objekts in die Schreibwarte f\u00fchrt.\u00a0<br \/>\nDie Aktualisierung der Eigenschaften von au\u00dfen sieht genau so aus wie die Arbeit mit einem POCO-Objekt:<\/p>\n<p><\/p>\n<pre><code class=\"cs\">myParent.Children.First().Property = \"Updated value\";<\/code><\/pre>\n<p><\/p>\n<p>Ein Objekt kann auf folgende Weisen entfernt werden:<\/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>Dabei wird das Objekt auch in die Warteliste zur L\u00f6schung eingereiht.<\/p>\n<p><\/p>\n<h2 id=\"kak-rabotaet-sohranenie\">Wie funktioniert das Speichern?<\/h2>\n<p><\/p>\n<p><em>ObjectRepository<\/em> bei \u00c4nderungen an \u00fcberwachten Objekten (sowohl beim Hinzuf\u00fcgen oder Entfernen als auch bei \u00c4nderungen der Eigenschaften) wird ein Ereignis <em>ModelChanged<\/em>, auf das <em>IStorage<\/em>, reagiert. Die Implementierungen <em>IStorage<\/em> sammeln bei Eintreten des Ereignisses die \u00c4nderungen in drei Warteschlangen \u2014 f\u00fcr Hinzuf\u00fcgungen, Aktualisierungen und L\u00f6schungen. <em>ModelChanged<\/em> \u00c4nderungen werden in drei Warteschlangen gespeichert \u2013 f\u00fcr Hinzuf\u00fcgungen, Aktualisierungen und L\u00f6schungen.<\/p>\n<p><\/p>\n<p>Auch die Implementierungen <em>IStorage<\/em> Bei der Initialisierung wird ein Timer erstellt, der alle 5 Sekunden die \u00c4nderungen speichert.\u00a0<\/p>\n<p><\/p>\n<p><em>Au\u00dferdem gibt es eine API f\u00fcr den erzwungenen Speicheraufruf: <strong>ObjectRepository.Save()<\/strong>.<\/em><\/p>\n<p><\/p>\n<p>Vor jedem Speicheraufruf werden zuerst sinnlose Operationen (z. B. duplizierte Ereignisse \u2013 wenn das Objekt zweimal ge\u00e4ndert wurde oder Objekte schnell hinzugef\u00fcgt\/entfernt wurden) aus den Warteschlangen entfernt, und erst dann erfolgt das eigentliche Speichern.\u00a0<\/p>\n<p><\/p>\n<p><em>In allen F\u00e4llen wird das aktuelle Objekt vollst\u00e4ndig gespeichert, sodass es m\u00f6glich ist, dass Objekte in einer anderen Reihenfolge gespeichert werden als sie ge\u00e4ndert wurden. Es k\u00f6nnen auch neuere Versionen von Objekten gespeichert werden, als zum Zeitpunkt der Hinzuf\u00fcgung zur Warteschlange.<\/em><\/p>\n<p><\/p>\n<h2 id=\"chto-est-eschyo\">Was gibt es noch?<\/h2>\n<p><\/p>\n<ul>\n<li>Alle Bibliotheken basieren auf .NET Standard 2.0. Sie k\u00f6nnen in jedem modernen .NET-Projekt verwendet werden.<\/li>\n<li>Die API ist thread-sicher. Die internen Sammlungen basieren auf <em>ConcurrentDictionary<\/em>, die Ereignisbehandler haben entweder Sperren oder ben\u00f6tigen diese nicht.\u00a0<br \/>\nDas einzige, woran man denken sollte, ist, beim Beenden der Anwendung <em>ObjectRepository.Save();<\/em><\/li>\n<li>Willk\u00fcrliche Indizes (erfordern Einzigartigkeit):<\/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\">Wer nutzt das?<\/h2>\n<p><\/p>\n<p>Ich pers\u00f6nlich habe begonnen, diesen Ansatz in all meinen Hobbyprojekten zu verwenden, weil es bequem ist und keine gro\u00dfen Investitionen in die Erstellung einer Datenspeicherschicht oder den Aufbau einer schweren Infrastruktur erfordert. F\u00fcr mich pers\u00f6nlich reicht in der Regel die Speicherung von Daten in litedb oder in einer Datei aus.\u00a0<\/p>\n<p><\/p>\n<p>In der Vergangenheit, als wir mit dem Team das inzwischen eingestellte Startup EscapeTeams (<em>dachte ich, hier kommt das Geld \u2013 aber nein, wieder nur Erfahrung<\/em>) betrieben haben, haben wir Azure Table Storage zur Datenspeicherung verwendet.<\/p>\n<p><\/p>\n<h2 id=\"plany-na-buduschee\">Zukunftspl\u00e4ne<\/h2>\n<p><\/p>\n<p>Ein zentrales Problem dieses Ansatzes, das behoben werden sollte, ist die horizontale Skalierung. Daf\u00fcr sind entweder verteilte Transaktionen erforderlich, oder man muss die Entscheidung treffen, dass dieselben Daten aus verschiedenen Instanzen nicht ver\u00e4ndert werden d\u00fcrfen, oder sie sollen nach dem Prinzip \"wer zuletzt kommt, mahlt zuletzt\" ver\u00e4ndert werden.<\/p>\n<p><\/p>\n<p>Technisch gesehen sehe ich das folgende Schema als m\u00f6glich an:<\/p>\n<p><\/p>\n<ul>\n<li>Anstelle eines objektorientierten Modells EventLog und Snapshot speichern.<\/li>\n<li>Andere Instanzen finden (sollten wir alle Endpunkte der Instanzen in den Einstellungen hinzuf\u00fcgen? UDP-Discovery? Master\/Slave?)<\/li>\n<li>EventLog zwischen den Instanzen \u00fcber einen Konsensalgorithmus wie RAFT replizieren.<\/li>\n<\/ul>\n<p><\/p>\n<p>Es gibt auch ein weiteres Problem, das mich besch\u00e4ftigt \u2014 die kaskadierte L\u00f6schung oder das Erkennen von F\u00e4llen, in denen Objekte gel\u00f6scht werden, auf die von anderen Objekten verwiesen wird.\u00a0<\/p>\n<p><\/p>\n<h2 id=\"ishodnyy-kod\">Quellcode<\/h2>\n<p><\/p>\n<p>Wenn Sie bis hierher gelesen haben \u2014 dann bleibt nur noch der Code zu lesen, den Sie auf GitHub finden k\u00f6nnen:<br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/DiverOfDark\/ObjectRepository\">https:\/\/github.com\/DiverOfDark\/ObjectRepository<\/a><\/noindex><\/p>\n<p>Quelle: <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\/de\/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=\"de_DE\" \/>\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\/de\/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-Muster f\u00fcr Ihre Heimprojekte | ProHoster","description":"Warum sollten alle Daten im Speicher gehalten werden? F\u00fcr die Speicherung von Website- oder Backend-Daten w\u00e4hlen die meisten gesund denkenden Personen zuerst eine SQL-Datenbank. Manchmal kommt jedoch die \u00dcberlegung auf, dass das Datenmodell nicht f\u00fcr SQL geeignet ist: Zum Beispiel ben\u00f6tigt man bei der Konstruktion von Suchen oder sozialen Graphen die Suche nach komplexen Beziehungen zwischen Objekten. Am schlimmsten ist es, wenn man im Team arbeitet.","canonical_url":"https:\/\/prohoster.info\/de\/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":"de_DE","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\/de\/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\/de\/wp-json\/wp\/v2\/posts\/33839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=33839"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/33839\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=33839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=33839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=33839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}