Ist es empfehlenswert, Entitätsobjekte als Datenübertragungsobjekte zu verwenden?


29

Ich frage mich, denn wenn ja, warum bietet Entity Framework keine Logik zum Erstellen eines neuen Objekts mit denselben Eigenschaften zum Übertragen von Daten zwischen Ebenen an?

Ich verwende die Entitätsobjekte, die ich mit dem Entitätsframework generiere.


3
Ich denke, das ist eine gute Frage, aber ich kann es nicht wirklich sagen, weil es so schwer zu lesen ist, dass ich nicht sicher bin, wie ich es beheben soll. Bitte bearbeiten Sie Ihre Frage.
candied_orange

1
@CandiedOrange +1, und es ist umso beängstigender, dass dies so viele positive Stimmen hat.
Guillaume31

Antworten:


23

Es liegt an dir.

Die meisten Leute werden Ihnen sagen, dass es keine gute Praxis ist, aber Sie können in einigen Fällen damit durchkommen.

EF hat aus mehreren Gründen nie gut mit DDD gespielt, aber zwei stechen heraus: Sie können keine parametrisierten Konstruktoren für Ihre Entitäten haben und Sie können keine Sammlungen einkapseln. DDD stützt sich darauf, da das Domänenmodell sowohl Daten als auch Verhalten enthalten sollte.

In gewisser Weise zwingt EF Sie zu einem anämischen Domänenmodell, und in diesem Fall können Sie die Entitäten als DTOs verwenden. Einige Probleme können auftreten, wenn Sie Navigationseigenschaften verwenden, aber Sie können diese Entitäten serialisieren und über das Netzwerk senden. Es kann jedoch nicht praktisch sein. Sie müssen die Serialisierung für jede Entität steuern, die Eigenschaften hat, die Sie nicht senden müssen. Der einfachere Weg besteht darin, separate Klassen zu entwerfen, die auf die Datenübertragung zugeschnitten sind. Zu diesem Zweck werden Bibliotheken wie AutoMapper erstellt.

Beispiel: Angenommen, Sie haben eine Klasse Personmit der folgenden Definition aufgerufen :

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; get; }

    // plus a bunch of other properties relevant about a person
}

Angenommen, Sie möchten irgendwo eine Liste der Mitarbeiter anzeigen, ist es möglicherweise sinnvoll, nur die Zeichen Id, FirstNameund zu senden LastName. Aber Sie müssen alle anderen irrelevanten Eigenschaften übermitteln. Es ist kein so großes Problem, wenn Sie sich nicht für die Größe der Antwort interessieren, aber die allgemeine Idee ist, nur die relevanten Daten zu senden. Auf der anderen Seite können Sie eine API entwerfen, die eine Liste von Personen zurückgibt. In diesem Fall ist möglicherweise das Senden aller Eigenschaften erforderlich. Daher ist es sinnvoll, die Entitäten zu serialisieren und zu senden. In diesem Fall ist das Erstellen einer DTO-Klasse umstritten. Manche Leute mögen es, Entities und DTOs zu verwechseln, andere nicht.

Um Ihre aktualisierte Frage zu beantworten, ist EF ein ORM. Seine Aufgabe besteht darin, Datenbankdatensätze Objekten zuzuordnen und umgekehrt. Was Sie mit diesen Objekten vor und nach dem Durchlaufen von EF tun, gehört nicht zu ihren Anliegen. Das sollte es auch nicht sein.


1
Kurz zusammengefasst. Was sind die Unterschiede zwischen DTOs und POCOs? Halten sie nicht einfach Daten?
Laiv

1
@ guillaume31 Sie können kein echtes Domain-Modell haben, ohne die Persistenz zu berücksichtigen. Was nützt eine öffentliche Schnittstelle, wenn ich gezwungen bin, Reflection zu verwenden (ganz zu schweigen von anderen Arten von Hacks, vorausgesetzt, mein öffentliches Eigentum wird von einem privaten Feld mit einem anderen Namen unterstützt), um meine Aggregate in einem gültigen Zustand zu laden? Wenn EF mir keine Infrastruktur zum Verbergen meiner Aggregate über die öffentliche Schnittstelle bietet, ist es besser, wenn ich meine Geschäftslogik an einem anderen Ort behalte und meine Domäne anämisch ist, anstatt eine zusätzliche Kesselplatte zum Laden aus der Datenbank zu schreiben.
Devnull

1
Sie möchten also lieber Ihr gesamtes Domain-Modell anämisch machen, als Ihren öffentlichen Sammlungs-Getter genauso zu benennen wie das private Feld? (Lassen Sie uns das Konstruktorproblem beiseite legen, da es in den meisten Fällen der Domäne zuwiderläuft, wenn ein Konstruktor alle Felder des Objekts belegt ...)
guillaume31

1
@Konrad von hier : As of EF Core 2.1, only services known by EF Core can be injected. Support for injecting application services is being considered for a future release.Ich lasse sehr gerne Anwendungsdienste in meine Entitäten einfließen .
Devnull

1
@Konrad Ich würde meine Domain-Entitäten nicht mehr als DTOs verwenden (wenn ich sie auf diese Weise verwenden würde). DTOs sind unabhängig von der Unterstützung von EF für Service Injection nützlich.
6.

8

Nein ist es nicht.

Im Idealfall stimmen DTOs mit Ihren Persistenz-Repositorys (auch bekannt als Ihre Datenbanktabellen) überein.

Aber Ihre Businessklassen sind nicht unbedingt eine Übereinstimmung. Möglicherweise benötigen Sie zusätzliche Klassen oder getrennte oder verknüpfte Klassen für Ihre Datenbank. Wenn Ihre Anwendung klein ist, sehen Sie diese Art von Problemen möglicherweise nicht wirklich. Bei mittleren bis großen Anwendungen tritt dies jedoch häufig auf.

Eine andere Sache ist, dass DTOs Teil der Domäne dessen sind, was mit Persistenz zu tun hat, während Ihre Business-Schicht nichts über sie wissen sollte.


Ein Command- Objekt ist ein DTO, über das die Business-Schicht etwas wissen sollte.
Devnull

Ich denke, die Business-Schicht wird das Befehlsobjekt wahrscheinlich indirekt über eine Schnittstelle aufrufen. Und ich meine DTOs wie bei den einfachen Objekten, die Daten enthalten, ohne jegliche Funktionalität. Ich bin nicht sicher, ob ein Befehlsobjekt ein DTO ist ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Juan Carlos Eduardo Romaina Ac

1
Normalerweise werden Befehle in den eigentlichen Befehl und seinen Handler unterteilt. Der Befehl enthält die Daten, der Handler enthält das Verhalten. Bei dieser Verwendung enthält der Befehlsteil nur die vom Client empfangenen Daten und fungiert als DTO zwischen dem Client und der Business-Schicht.
2.

DTO fließen nicht von der Persistenz in die Domäne, sondern können auch von außen kommen, wie beim Datenaustausch (denken Sie an REST-APIs). Wie von devnull angedeutet, handelt es sich bei Befehlen und Ereignissen in gewisser Weise um DTOs, die an die Business-Schicht übertragen werden. Ob Handler Business Layer sind oder nicht, hängt vom Design ab.
Laiv

4

Das ist eigentlich eine sehr schlechte Idee. Martin Fowler hat einen Artikel über lokale DTOs .

Kurz gesagt, DTOPattern wurde zum Übertragen von Daten außerhalb des Prozesses verwendet, z. B. über den Draht und nicht zwischen Schichten innerhalb desselben Prozesses.


Wie bei allen Programmieransätzen gibt es keine Einheitsgröße, sonst würden wir nicht in jeder Anwendung, die wir entwickeln, unterschiedliche Muster und Ansätze diskutieren und diskutieren, sondern immer die gleichen Dinge verwenden. DTOs sind im Wesentlichen nur POPOs, die nur benannt wurden, um eine Absicht zu zeigen. Die Verwendung eines DTO zum "Übertragen" von Daten zwischen z. B. Dienst, Steuerung und Sicht hat nichts zu bedeuten. Es gibt nichts im Namen oder in der Struktur der Klassen, was angibt oder einschränkt, von wo und zu welchen Daten Daten übertragen werden
James,

4

Nein, es ist eine schlechte Praxis.

Einige Gründe:

  1. Neue Entitätsfelder befinden sich standardmäßig im Dto . Entität verwenden bedeutet, dass alle Informationen standardmäßig verfügbar sind. Dies kann dazu führen, dass Sie sensible Informationen preisgeben oder zumindest Ihren API-Vertrag aufblähen, der viele Informationen enthält, die nicht für diejenigen verwendet werden, die die API verwenden. Natürlich können Sie Felder mit einigen Anmerkungen (wie @JsonIgnorein der Java-Welt) ignorieren , aber dies führt zum nächsten Problem ...
  2. Viele Anmerkungen / Bedingungen / Kontrollen zur Entität . Sie müssen steuern, was Sie an Dto senden möchten, wenn sich ein Attributname ändert (dies bricht den Vertrag), ein Attribut hinzufügen, das nicht von der Entität stammt, die Reihenfolge der Attribute usw. Bald werden Sie Ihr einfaches sehen Entität mit vielen Anmerkungen, zusätzlichen Feldern und jedes Mal wird es schwieriger sein zu verstehen, was passiert.
  3. Weniger Flexibilität . Mit einem Dto können Sie die Informationen in mehrere Klassen aufteilen, die Attributnamen ändern, neue Attribute hinzufügen usw. Mit einer Entität wie Dto ist dies nicht so einfach.
  4. Nicht optimiert . Ihre Entität wird immer größer sein als eine einfache Dto. So haben Sie immer mehr Informationen, die ignoriert / serialisiert werden müssen, und möglicherweise werden mehr unnötige Informationen übertragen.
  5. Faule Probleme . Wenn Sie mit der Entität einiger Frameworks (z. B. Ruhezustand) versuchen, Informationen abzurufen, die zuvor nicht faul in eine Datenbanktransaktion geladen wurden, wird der ORM-Proxy nicht an die Transaktion angehängt, und Sie erhalten eine Art "fauler Ausnahmefehler". nur um eine getMethode der Entität aufzurufen .

So ist es einfacher und sicherer, eine Art Mapper-Tool zu verwenden, das Ihnen bei diesem Job hilft und die Entitätsfelder einem Dto zuordnet.


1

Um das zu vervollständigen, was @Dherik gesagt hat, sind die Hauptprobleme bei der Verwendung von Entitätsobjekten als Datenübertragungsobjekte:

  1. In einer Transaktion gehen Sie das Risiko ein, Änderungen an Ihrer Entität festzuschreiben, da Sie diese als DTO verwenden (selbst wenn Sie die Entität der Sitzung in einer Transaktion trennen können, müssen Sie diesen Status meistens vorher überprüfen Änderungen an Ihrem Entity-DTO und stellen Sie sicher, dass Sie sich nicht in einer Transaktion befinden oder dass die Sitzung geschlossen wurde, wenn Sie nicht möchten, dass die Änderungen beibehalten werden).

  2. Die Größe der Daten, die Sie zwischen dem Client und dem Server gemeinsam nutzen: Manchmal möchten Sie nicht den gesamten Inhalt einer Entität an den Client senden, um die Größe der Antwort der Anforderung zu minimieren. Die Trennung des DTO von der Entität ist flexibler, um die Daten, die Sie in bestimmten Anwendungsfällen senden möchten, zu spezialisieren.

  3. Sichtbarkeit und Wartung: Sie müssen Ihre jpa / hibernate-Annotationen in den Feldern Ihrer Entität verwalten und die jackson-Annotationen für die Serialisierung in json an derselben Stelle verwalten (auch wenn Sie sie von der Entitätsimplementierung trennen können, indem Sie sie in die von der geerbte Schnittstelle einfügen Entität). Wenn Sie dann Ihren DTO-Inhalt ändern, indem Sie ein neues Feld hinzufügen, kann eine andere Person wahrscheinlich annehmen, dass es sich um ein Feld der Entität handelt, also um ein Feld der betreffenden Tabelle in Ihrer Datenbank (auch wenn Sie die @TransientAnnotation für alle Ihre DTO-Felder verwenden können Im Falle ..!).

Meiner Meinung nach macht es beim Lesen der Entität Geräusche, aber meine Meinung ist sicherlich subjektiv.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.