Verwalten von DTOs und Mapping im großen .NET-Projekt

8

Mein Team und ich erstellen große .NET WinForms-Anwendungen. Die Anwendung verwendet verschiedene "Dienste", um Daten von und zu unserer Datenbank zu erhalten. Jeder "Dienst" lebt in seiner eigenen Lösung und behandelt eine bestimmte Art von Daten. So verwaltet beispielsweise unser "ContactsService" Kontakte in unserer Datenbank.

Normalerweise haben wir für jeden Dienst DTOs erstellt. Also haben wir vielleicht ein "ContactDTO", das einfache String-Eigenschaften für jedes Stück Daten auf dem Kontakt hat. Jetzt haben wir auch eine Business-Schicht "Contact" -Klasse, die genau die gleichen Eigenschaften und vielleicht ein paar zusätzliche Methoden mit etwas Geschäftslogik hat. Darüber hinaus hat der "ContactsService" eine eigene Contact-Klasse, die von ContactDTO hydratisiert wird.

Es ist zu einem großen Problem geworden, all unsere DTOs und Kartierungen zu verwalten. Derzeit sieht das Senden eines Kontakts in der Datenbank wie folgt aus:

  • Kunden zuordnen Kontakt zu ContactDTO
  • Karte von ContactDTO zum Service Kontakt
  • Kontakt speichern
  • Kartenservice Kontakt zu ContactDTO
  • Karte KontaktDTO zum Kunden Kontakt

Das fühlt sich einfach beschissen an. Wenn wir unserer Client Contact-Klasse eine Eigenschaft hinzufügen, müssen wir die Eigenschaft und die Zuordnungen an 3-4 Stellen hinzufügen.

Was machen wir falsch und wie können wir unser Leben einfacher machen? Wäre es einfacher, etwas wie Json.NET zu verwenden und JSON DTOs zu haben? Wir haben AutoMapper ausgecheckt, aber einige Teammitglieder fanden es zu kompliziert.

    
TaylorOtwell 06.07.2011, 18:53
quelle

3 Antworten

2

Ich bin schon oft darauf gestoßen, aber in meinem Fall habe ich beschlossen, es zu akzeptieren, weil die Entscheidung, DTOs zu verwenden, eine absichtliche war - ich möchte meinen Dienst, meinen Client, meinen Proxy, und Vertragsabsprachen sauber getrennt werden.

Bei der Verwendung von WCF ist das Layout, das ich bevorzuge, ungefähr so ​​(unter Verwendung Ihres Kontaktbeispiels):

  • Client-Assembly
    • Kontakt (hat clientspezifische Merkmale)
  • Shared-Verträge-Assembly
    • Kontakt (der vereinbarte gemeinsame DTO)
  • Proxy-Assembly
    • Verwendet den Kontakt aus der freigegebenen Contracts-Assembly
  • Servicemontage
    • Kontakt (hat Service-y-Geschäftslogikmerkmale, z. B. kann dies der Typ sein, der von einem ORM-Layer wie Entity Framework bereitgestellt wird)

Ich teile jetzt die Verträge zwischen dem Dienst und dem Kunden. Wenn ich sie unabhängig voneinander versionieren muss, kann ich einfach eine Kopie der freigegebenen Contracts-Assembly erstellen und die Proxy-Assembly neu ausrichten, um die Kopie zu verwenden, und dann die beiden Contracts-Assemblys unabhängig voneinander ändern. Aber in den meisten Fällen, in denen ich gearbeitet habe, besitze ich sowohl den Kunden als auch den Service. Daher ist es praktisch, die Contracts-Assembly zwischen den beiden zu teilen.

Das ist die einzige Optimierung, die ich mir vorstellen kann, wenn Sie die Architekturentscheidung treffen, Ihre Komponenten mit DTOs zu isolieren, zumindest ohne Code-Generierungs-Tools zu verwenden (ich kenne keine guten, muss aber nicht suchen) in sie).

Bearbeiten: Wenn Sie WCF nicht verwenden, benötigen Sie natürlich nicht die 'Proxy' Assembly.

    
Lars Kemmann 06.07.2011, 23:14
quelle
0

AutoMapper ist nicht besonders kompliziert. Wenn Sie den Konventionen folgen, z.B. Contact.Address1 wird ContactAddress1 auf dem DTO Sie müssen nicht viel Code abgesehen von dem Aufruf von Mapper.Map schreiben. Alternativ können Sie Code-Generierung verwenden, aber es wird immer noch schwierig, Änderungen zu verwalten.

Darf ich fragen, warum Sie eine KontaktDTO und einen Service-Kontakt benötigen? Kannst du nicht einfach den Service Contact herumreichen? Ich weiß, dass es nicht die beste Übung ist, aber es könnte dich vor RSI retten.

BEARBEITEN: Mein letzter Punkt wurde ignoriert - aus irgendeinem Grund dachte ich, dass Sie den Dienstkontakt einer Datenbank-Entität wie NHibernate / Entity Framework

zuordnen würden     
user528573 06.07.2011 20:07
quelle
0

Einige Dinge, um den Prozess zu beschleunigen:

Ich habe einen Code-Generator geschrieben, mit dem Sie die Tabelle (n) und Spalten aus der Datenbank auswählen und ein C # DTO generieren lassen können. Dies spart viel unnötiges Tippen und kann DTOs viel schneller generieren. Ein wenig Zeit im Voraus, aber wenn Sie einen Tisch mit 20 Spalten haben, die Sie zuordnen müssen, hilft es.

Ich habe auch Code-Generatoren geschrieben, um die DTOs für gespeicherte Prozeduren für Speicher-, Lösch- und Abfrageoperationen abzubilden. Wieder eine Zeitersparnis, weil viele von ihnen sehr ähnlich sind. Wenn Sie viel langwierigen "Grunt" -Code geschrieben haben, denken Sie an einen Code-Generator, um es zu tun.

Verwenden Sie ein Entitätsframework oder einen ORM-Mapper für das Back-End. Dies kann viel Zeit sparen, aber Sie müssen in das ORM-Wissen investieren und lernen, wie es funktioniert.

Erstellen Sie einen allgemeinen Satz von DTOs, die vom Client zur Datenbank verwendet werden. Dies ist möglicherweise in einigen Situationen nicht praktikabel, wenn Sie Proxies oder kleinere DTOs für den Client benötigen, aber Sie können versuchen, einige allgemeine DTOs zu haben, die vom Client an den Server zurückübertragen werden.

Entfernen Sie einige der Ebenen. Ich weiß, dass das ein bisschen ein Anti-Muster klingt, aber in einigen Fällen muss die Zwiebel nicht so dick sein.

    
Jon Raynor 06.07.2011 23:29
quelle

Tags und Links