Informationen zu Entitäten, DTO, ORM und Lazy Load

Objektorientiertes Paradigma ist der Standard für Anwendungssoftware. Relationales DBMS - ein Standard zum Speichern von Daten in Anwendungssoftware. Ja, Sie können in Haskell schreiben und Daten ausschließlich in ClickHouse speichern. Aber es geht um den Mainstream.

Mit ORM können Sie eine Eule auf einen Globus ziehen, um so zu tun, als gäbe es kein RDBMS, und die Daten werden in einem Objektmodell gespeichert, das für OOP besser geeignet ist. Es bleibt ein "kleines" solches Problem - diese Abstraktion "fließt" wie viele andere. Wo im Objektmodell eine Verknüpfung zu einem anderen Objekt im Datenbank-Fremdschlüssel und der ID besteht. Zum Zeitpunkt der Materialisierung des Unternehmens stehen wir vor der Wahl:

  1. Laden Sie alles herunter und verlieren Sie Speicherplatz
  2. Geben Sie explizit an, welche Abhängigkeiten wir herunterladen möchten und welche nicht, und verstoßen Sie gegen das Tell-Don't-Ask- Prinzip
  3. Laden Sie Abhängigkeiten implizit nach Bedarf mit Lazy Load und erhalten Sie Leistungsprobleme irgendwo im aufgerufenen Code

Welche Art von Bein sollten Sie abschneiden: links oder rechts?

TLDR Lazy Load ist nicht so schlecht, wenn es nur zum Schreiben und nicht zum Lesen verwendet wird. Aber alles ist nicht so einfach und es gibt viele Nuancen.

Im Laufe der Zeit kam ich zu dem Schluss, dass Lazy Load und / oder die Abhängigkeit von Entitäten von der Implementierung von ORM unter bestimmten Bedingungen das geringere Übel ist.

Lesen Sie im gelesenen Subsystem immer nur DTO


In 90% der Fälle treten Probleme mit Lazy Load genau beim Lesen auf. Wir erhalten die Liste der Entitäten, gehen sie durch und beginnen mit der Schleife und beginnen mit der Auswahl aller erforderlichen Daten. Wir erhalten eine Reihe von Anfragen an die Datenbank. In diesem Fall müssen in den meisten Fällen nur die Daten abgerufen, serialisiert und in Form von JSON zurückgesendet werden. Warum dann überhaupt Entitäten laden? Es ist nicht erforderlich, diese Daten zum Änderungs-Tracker-UOW hinzuzufügen, um die gesamte Entität zusammen mit den "zusätzlichen" Feldern zu lesen. Stattdessen können Sie immer entweder Select oder ProjectTo schreiben. Lazy Load ist nicht erforderlich, da der C # -Code von Select in SQL übersetzt und auf der Datenbankseite ausgeführt wird.

Was ist, wenn meine Logik nicht in SQL übersetzt wird?


Ich empfehle, die Kundenbewertung auszuschalten. Erstens können Sie direkt in sub "helfen" und Unterstützung für die erforderlichen Funktionen hinzufügen. Keine schlechte Option, wenn es um einfaches Computing geht, nicht um Geschäftsregeln. Option Nummer zwei: Extrahieren Sie die Schnittstelle aus der Entität und implementieren Sie sie sowohl in der Entität als auch im DTO.

In der Datenbank gibt es beispielsweise zwei Felder: "Preis ohne Rabatt" und "Preis mit Rabatt". Wenn das Feld "Rabattpreis" ausgefüllt ist, verwenden Sie es, wenn nicht, verwenden Sie das Feld mit dem üblichen Preis. Fügen Sie eine weitere Regel hinzu. Beim Kauf von 3 Produkten zahlen Sie nur für die 2 teuersten, wobei auch regelmäßige Rabatte berücksichtigt werden.

Die Implementierung kann wie folgt sein:

 public interface IHasProductPrice { decimal BasePrice { get; } decimal? SalePrice { get; } } public class Product: IHasProductPrice { // ... a lot of code public decimal BasePrice { get; protected set;} public decimal? SalePrice { get; protected set;} } public class ProductDto: IHasProductPrice { public decimal BasePrice { get; set;} public decimal? SalePrice { get; set;} } public static class ProductCalculator { public static void decimal Calculate(IEnumerable<IHasProductPrice> prices) } 

Im Schreibsubsystem ist Lazy Load nicht so beängstigend


Im Schreibsubsystem hingegen reicht oftmals nur die ID zum Schreiben nicht aus. Bei allen Arten von Überprüfungen lesen Sie häufig die gesamte Entität, da das Objektparadigma das Kombinieren von Daten und Operationen innerhalb des Klassenobjekts und seiner Invariante umfasst. Wenn das Projekt DDD verwendet, müssen Schreib- / Änderungsvorgänge über den Aggregationsstamm ausgeführt werden und daher nur über ein Objekt und seine Abhängigkeiten. Eine große Anzahl von Abfragen kann nur auftreten, wenn mit verwandten Sammlungen gearbeitet wird.

Zugehörige Sammlungen in Aggregaten


Wenn sich zu viele Daten in der Maschine befinden, kann dies auf ein Konstruktionsproblem hinweisen. Typische Wurzeln der Aggregation - Korb, Bestellung, Paket. Normalerweise arbeiten die Benutzer nicht mit Daten aus Tausenden von Zeilen. Daher ist das Herunterladen der gesamten verknüpften Sammlung möglicherweise nicht die produktivste, aber keine tödliche Operation. Wenn sich jedoch Tausende von Objekten in der Sammlung befinden, ist es möglich, dass es wirklich keine solche Aggregationswurzel gibt, und die Entwickler haben sich diese ausgedacht, da dies mit improvisierten Werkzeugen sehr einfach war.

Was ist, wenn insgesamt noch Tausende von Datensätzen vorhanden sind?


DbContext den DbContext an den Konstruktor und lesen Sie daraus nur die Daten, die im Kontext der Operation erforderlich sind. Ja, DIP verletzen. Entweder das, oder verwenden Sie das Gerät in diesem Fall überhaupt nicht.

Massenoperationen


Das Importieren einer Datei mit 10.000 Zeilen ist ein großartiges Ziel für Lazy Load. Hier werden zu allen Problemen des Lesesubsystems auch die Bremsen von ChangeTracker hinzugefügt. Für die Massenaufzeichnung müssen Sie separate Tools verwenden . Ich bevorzuge Batch-Erweiterungen, da Sie auch hier auf das Erstellen von Entitäten verzichten können. Für besonders schwere Fälle gibt es gute alte gespeicherte Prozeduren und sogar spezielle DBMS-Tools .

Life Hack


Wenn Sie sowohl eine Massenoperation als auch eine konventionelle implementieren müssen, müssen Sie mit einer Massenoperation beginnen. Ein normaler Betrieb ist nur ein Sonderfall von Massencode in einer Sequenz mit nur einem Element.

Source: https://habr.com/ru/post/de437418/


All Articles