Ich habe viele Fragen im Zusammenhang mit der Zuordnung von DTOs zu Domänenobjekten gesehen , aber ich hatte nicht das Gefühl, dass sie meine Frage beantwortet haben. Ich habe schon viele Methoden angewendet und habe meine eigene Meinung, aber ich suche etwas Konkreteres.
Die Situation:
Wir haben viele Domain-Objekte. Wir verwenden ein CSLA-Modell, sodass unsere Domänenobjekte sehr komplex sein können und ihren eigenen Datenzugriff enthalten. Sie möchten diese nicht auf dem Draht weitergeben. Wir werden einige neue Dienste schreiben, die Daten in einer Reihe von Formaten (.Net, JSON usw.) zurückgeben. Aus diesem (und anderen Gründen) erstellen wir auch ein schlankes Datenübertragungsobjekt, das auf dem Draht herumgereicht werden soll.
Meine Frage ist: Wie sollen das DTO- und das Domain-Objekt verbunden werden?
Meine erste Reaktion ist die Verwendung einer Fowler-DTO-Musterlösung . Ich habe das schon oft gesehen und es fühlt sich für mich richtig an. Das Domänenobjekt enthält keinen Verweis auf das DTO. Eine externe Entität (ein "Mapper" oder "Assembler") wird aufgerufen, um ein DTO aus einem Domänenobjekt zu erstellen. Normalerweise befindet sich auf der Domänenobjektseite ein ORM . Der Nachteil dabei ist, dass der "Mapper" für jede reale Situation extrem komplex wird und sehr zerbrechlich sein kann.
Eine andere Idee ist, dass das Domänenobjekt das DTO "enthält", da es nur ein schlankes Datenobjekt ist. Die Domänenobjekteigenschaften verweisen intern auf die DTO-Eigenschaften und können das DTO nur zurückgeben, wenn Sie dazu aufgefordert werden. Ich kann keine Probleme damit sehen, aber es fühlt sich falsch an. Ich habe einige Artikel gesehen, in denen Leute, die NHibernate verwenden, diese Methode zu verwenden schienen .
Gibt es andere Möglichkeiten? Lohnt sich eine der oben genannten Möglichkeiten? Wenn ja oder wenn nicht, warum?
quelle
Antworten:
Ein Vorteil eines Mappers zwischen Ihrer Domain und Ihrem DTO ist nicht so offensichtlich, wenn Sie nur eine einzelne Zuordnung unterstützen. Wenn jedoch die Anzahl der Mappings zunimmt, hilft die Isolierung dieses Codes von der Domain, die Domain einfacher und schlanker zu halten. Sie werden Ihre Domain nicht mit viel zusätzlichem Gewicht überladen.
Persönlich versuche ich, die Zuordnung von meinen Domänenentitäten fernzuhalten und die Verantwortung in die sogenannte "Manager / Service-Schicht" zu legen. Dies ist eine Schicht, die sich zwischen der Anwendung und dem / den Respository (s) befindet und Geschäftslogik wie die Workflow-Koordination bereitstellt (Wenn Sie A ändern, müssen Sie möglicherweise auch B ändern, damit Service A mit Service B zusammenarbeitet).
Wenn ich viele mögliche Endformate hätte, könnte ich einen steckbaren Formatierer erstellen, der das Besuchermuster verwenden könnte, um beispielsweise meine Entitäten zu transformieren, aber ich habe noch keinen Bedarf für etwas so Komplexes gefunden.
quelle
Sie könnten einen Automapper wie den von Jimmy Bogard verwenden, der keine Verbindung zwischen den Objekten hat und auf der Einhaltung von Namenskonventionen beruht.
quelle
Wir verwenden T4-Vorlagen, um die Mapping-Klassen zu erstellen.
Pro's - von Menschen lesbarer Code, der zur Kompilierungszeit verfügbar ist und schneller als ein Laufzeit-Mapper ist. 100% Kontrolle über den Code (kann Teilmethoden / Vorlagenmuster verwenden, um die Funktionalität auf Ad-hoc-Basis zu erweitern)
Con's - ohne bestimmte Eigenschaften, Sammlungen von Domänenobjekten usw., Erlernen der T4-Syntax.
quelle
Wenn Sie die Zuordnungslogik in Ihrer Entität behalten, ist Ihrem Domänenobjekt jetzt ein "Implementierungsdetail" bekannt, über das es nichts wissen muss. Im Allgemeinen ist ein DTO Ihr Gateway zur Außenwelt (entweder von einer eingehenden Anfrage oder über einen Lesevorgang von einem externen Dienst / einer externen Datenbank). Da die Entität Teil Ihrer Geschäftslogik ist, ist es wahrscheinlich am besten, diese Details außerhalb der Entität zu halten.
Das Mapping woanders zu behalten wäre die einzige Alternative - aber wohin sollte es gehen? Ich habe versucht, Mapping-Objekte / -Dienste einzuführen, aber nachdem alles gesagt und getan war, schien es wie Überentwicklung (und war es wahrscheinlich). Ich hatte einige Erfolge mit Automapper und dergleichen für kleinere Projekte, aber Tools wie Automapper haben ihre eigenen Fallstricke. Ich hatte einige ziemlich schwer zu findende Probleme im Zusammenhang mit Zuordnungen, da die Zuordnungen von Automapper implizit und vollständig vom Rest Ihres Codes entkoppelt sind (nicht wie "Trennung von Bedenken", sondern eher wie "Wo lebt die gottverlassene Zuordnung?") kann manchmal schwer zu finden sein. Um nicht zu sagen, dass Automapper seine Verwendung nicht hat, weil es tut. Ich denke nur, Mapping sollte so offensichtlich und transparent wie möglich sein, um Probleme zu vermeiden.
Anstatt eine Mapping-Service-Schicht zu erstellen, hatte ich viel Erfolg damit, meine Mappings in meinen DTOs zu behalten. Da DTOs immer an der Grenze der Anwendung sitzen, können sie auf das Geschäftsobjekt aufmerksam gemacht werden und herausfinden, wie sie von / zu ihnen zugeordnet werden können. Selbst wenn die Anzahl der Zuordnungen auf einen angemessenen Wert skaliert wird, funktioniert dies sauber. Alle Zuordnungen befinden sich an einem Ort, und Sie müssen nicht eine Reihe von Zuordnungsdiensten in Ihrer Datenschicht, Antikorruptionsschicht oder Präsentationsschicht verwalten. Stattdessen ist das Mapping nur ein Implementierungsdetail, das an das an der Anforderung / Antwort beteiligte DTO delegiert ist. Da Serialisierer im Allgemeinen nur Eigenschaften und Felder serialisieren, wenn Sie sie über das Kabel senden, sollten Sie auf keine Probleme stoßen. Persönlich fand ich dies die sauberste Option und ich kann meiner Erfahrung nach sagen:
quelle
Wie sehen Sie die Implementierung eines Konstruktors in der DTO-Klasse, der ein Domänenobjekt als Parameter verwendet?
Sag ... so etwas
class DTO { // attributes public DTO (DomainObject domainObject) { this.prop = domainObject.getProp(); } // methods }
quelle
DTO
und derDomainObject
, bemühen wir uns grundsätzlich, dass dieses Problem des DTO vom Domänenobjekt abhängt, sodass alle "Bauarbeiten" in einer mittleren Ebene (Klasse) ausgeführt werdenmapper
, die von beiden DTOs abhängig ist und DomainObjects. Das ist also der beste oder allgemein empfohlene Ansatz für diese Angelegenheit? Ich möchte nur sicherstellen, dass der Punkt verstanden wurde.Eine weitere mögliche Lösung: http://glue.codeplex.com .
Eigenschaften:
quelle
Sie können auch Otis ausprobieren, einen Objekt-zu-Objekt-Mapper. Konzepte ähneln der NHibernate-Zuordnung (Attribut oder XML).
http://code.google.com/p/otis-lib/wiki/GettingStarted
quelle
Ich kann ein Tool vorschlagen, das ich erstellt habe und das Open Source ist und das bei CodePlex gehostet wird: EntitiesToDTOs .
Die Zuordnung von DTO zu Entity und umgekehrt wird durch Erweiterungsmethoden implementiert, die die Assembler-Seite jedes Endes bilden.
Sie enden mit Code wie:
Foo entity = new Foo(); FooDTO dto = entity.ToDTO(); entity = dto.ToEntity(); List<Foo> entityList = new List<Foo>(); List<FooDTO> dtoList = entityList.ToDTOs(); entityList = dtoList.ToEntities();
quelle
Warum können wir das nicht so machen?
class UserDTO { } class AdminDTO { } class DomainObject { // attributes public DomainObject(DTO dto) { this.dto = dto; } // methods public function isActive() { return (this.dto.getStatus() == 'ACTIVE') } public function isModeratorAdmin() { return (this.dto.getAdminRole() == 'moderator') } } userdto = new UserDTO(); userdto.setStatus('ACTIVE'); obj = new DomainObject(userdto) if(obj.isActive()) { //print active } admindto = new AdminDTO(); admindto.setAdminRole('moderator'); obj = new DomainObject(admindto) if(obj.isModeratorAdmin()) { //print some thing }
@FrederikPrijck (oder) jemand: Bitte vorschlagen. Im obigen Beispiel hängt DomainObject von DTO ab. Auf diese Weise kann ich den Code für die Zuordnung des Domänenobjekts dto <--> vermeiden.
oder DomainObject-Klasse kann die DTO-Klasse erweitern?
quelle
Eine andere Option wäre die Verwendung von ModelProjector . Es unterstützt alle möglichen Szenarien und ist sehr einfach bei minimalem Platzbedarf zu verwenden.
quelle
Wir können dafür Factory-, Memento- und Builder-Muster verwenden. Werkseitig verbergen Sie die Details zum Erstellen einer Instanz des Domänenmodells aus DTO. Memento kümmert sich um die Serialisierung / Deserialisierung des Domänenmodells zu / von DTO und kann sogar auf private Mitglieder zugreifen. Der Builder ermöglicht die Zuordnung von DTO zu Domäne mit fließender Schnittstelle.
quelle