2014-05-02 8 views
7

Ich war neugierig, was die Leute denken über die ID einer DAL-Entität als eine Eigenschaft der Domain-Entity zu halten, bei der absolutesten eine Read-Only-Eigenschaft.Persistence IDs und Domain Model Entities

Meine ersten Gedanken waren, dass dies in Ordnung ist, aber je mehr ich darüber nachdenke, desto mehr mag ich die Idee nicht. Nachdem dem gesamten Domänenmodell nicht bewusst ist, wie die Daten persistiert werden, ist das Halten und die Id-Eigenschaft für jedes Domänenmodell eine weniger als subtile Indikation. Die Persistenzschicht kann etwas sein, das keine Primärschlüssel benötigt, oder eine andere Eigenschaft, die in dem Domänenmodell exponiert ist, kann ein geeigneter Kandidat für die Identifikation sein, eine Modell-Nr. vielleicht.

Aber dann dachte ich, dass Domain-Modelle, die keine zuverlässige Möglichkeit zur eindeutigen Identifizierung eines Eintrags in einer Datenbank-Persistenz-Schicht haben, wie identifizieren sie Einträge beim Aktualisieren oder Löschen?

Ein Wörterbuch, das auf schwachen Referenzschlüsseln basiert, könnte den Trick machen; WeakDictionary<DomainEntity, PrimaryKeyType>. Dieses Wörterbuch wäre ein Teil der Repository-Implementierung, wenn der Client des Repositorys Fetch eine Sammlung von DomainEntity eine schwache Referenz auf die Entität und seine Persistenzschicht-ID in diesem internen Wörterbuch wie dann gespeichert wird, wenn Zeit kommt, um die modifizierte zurückzugeben Einheit in das Repository für die Persistenz-Schicht zu aktualisieren, könnte die folgenden zurück, um die Id

PrimaryKeyType id = default(PrimaryKeyType); 
if (!weakDictionary.TryGetValue(someDomainEntity, out id)) 
    // id not found, throw exception? custom or otherwise.. 

// id found, continue happily mapping domain model back to data model. 

die Vorteile dieses Ansatzes zu erhalten getan werden, wie ich es sehe, ist die Domäne Entität halten muss nicht seine Persistenz-Schicht spezifische ID und Das Repository zwingt Sie, eine legitime Domain-Entität zu haben, die entweder durch einen Aufruf an eine Fetch...-Methode oder die Add/CreateNew-Methode, z Wenn Sie versuchen, die Entität zu aktualisieren/zu löschen, wird eine Ausnahme ausgelöst.

Ich bin mir bewusst, dass dies wahrscheinlich über-engineering und ich sollte nur schnallen und pragmatisch werden, war ich nur neugierig auf was andere Leute darüber denken.


Ich möchte nicht einen anderen Thread nur für diese kleine Frage starten, da es etwas verwandt ist. Aber da ich erst vor relativ kurzer Zeit nach DDD geschaut habe (obwohl in diesem Fall meine Datenbank an erster Stelle stand), fragte ich mich, ob ich bestätigen könnte, dass ich die richtige Einstellung für Domain Entities habe. Hier ist ein Beispiel für meine Employee Domain Entity.

public class Employee : DomainEntity 
{ 
    public string FirstName { get; } 
    public string LastName { get; } 
    public UserGroup Group { get; } 
    // etc.. 


    // only construct valid employees 
    public Employee(string firstName, string lastName, SecureString password, UserGroup group); 

    // validate, update. (not sure about this one.. pulled it 
    // from an open source project, I think that names should be able to be set individually). 
    AssignName(string firstName, string lastName); 

    // validate, update. 
    ResetPassword(SecureString oldPassword, SecureString newPassword); 

    // etc.. 
} 

Vielen Dank!

+0

Sie sollten ein wenig auf den Müll reduzieren und eine _real_ Frage stellen (keine Diskussion), wenn Sie möchten, dass diese Frage beantwortet wird (und offen bleiben) – Shoe

+4

@ShoeMay: Ich stimme nicht zu. Dies ist eine relevante und gut strukturierte Frage. Diese Implementierungskonzepte von DDD werden durch Designfragen wie diese oft stark belastet. – davenewza

Antwort

4

Ihr Vorschlag, schwache Referenzen zu verwenden, weist einen großen Fehler auf.

Wie Sie vielleicht wissen, haben Domain-Entitäten die wichtige Eigenschaft, dass sie Identität haben müssen. Dies ist aus Vergleichsgründen wichtig. Wenn zwei Einheiten die gleiche Identität haben, unabhängig von den Werten ihrer Eigenschaften, so wird sie als gleich betrachtet:

Entity1 == Entity2 ⇔ Entity1.Identity == Entity2.Identity 

Ein typisches „Entwurfsmuster“ wäre, alle Einheiten von einer DomainEntity<T> abstrakten Klasse zu erben, die das überschreibt Vergleich dieser Objekte und vergleicht nach Identität.

Betrachten Sie nun Ihren Ansatz, eine schwache Referenz zu verwenden. Nehmen wir ein Beispiel:

Sie holen einen Entity1, sagen Sie den "Reegan Layzell" Benutzer aus einem Repository.Dann holen Sie die exakt gleiche "Reegan Layzell" -Entität erneut aus dem Repository als Entity2. Sie haben jetzt dieselbe Entität in Ihrer Domäne in zwei Objekten. Aber sie haben (natürlich) unterschiedliche Referenzen.

Beim Vergleich werden diese Entitäten in Ihrer Domäne nicht als gleich angesehen.

Ich bewundere Ihre Angst der Datenbank betrifft in Ihrer Domain-Modell einzuführen, sondern die Datenbank-ID in Ihre Entitäten ausbreitende kaum die Qualität Ihrer Modelle beeinflussen gehen und es wird Ihnen eine Menge Ärger sparen. Wie Sie gesagt haben, müssen wir pragmatisch sein.

In Bezug auf Ihre Employee Beispiel: Ist AssignName wirklich sinnvoll? Kann sich der Name eines Mitarbeiters tatsächlich nach der Erstellung ändern? Ansonsten sieht es so aus, als hättest du die richtige Idee. Ich empfehle Ihnen dringend, dies zu beobachten: Crafting Wicked Domain Models von Jimmy Bogard.

+0

Eigentlich war ich mir dieses Problems bewusst und löste es, indem ich eine Reihe von privaten Klassen in meiner 'WeakDictionary'-Implementierung implementierte. Eine davon macht einen Vergleich zwischen den schwachen Referenzen durch Überschreiben der Equals/GetHashCode-Methoden über die "Identität" der schwach referenzierten Entität. Das Problem, das ich jetzt habe, ist das automatische Entfernen der Entität aus dem Wörterbuch, wenn die Referenz verloren gegangen ist. Es gibt keinen Haken für mich, um so etwas zu tun .. zumindest leicht. Es ist immer noch eine Arbeit im Gange, aber hier, werfen Sie einen Blick http://pastebin.com/Vt73HJzk – rtlayzell

+0

Ich habe das Szenario getestet, das Sie erwähnt und alles funktionierte gut, die Klasse selbst ist ein WIP und ich benutze einen Timer, um das zu tun automatische Bereinigung (Adhoc-Lösung), großartige Verbindung übrigens, ich habe es schon vorher gesehen, aber es sollte mehr Videos geben, die DDD abdecken. – rtlayzell

+0

Auch ich bin zu der Erkenntnis gekommen, dass diese technischen IDs notwendig sind, um große Aggregate aufzulösen das muss nur auf eine bestimmte Entität verweisen, anstatt dafür verantwortlich zu sein. Zum Beispiel in einem meiner Projekte habe ich eine "Appointment" aggregierte Wurzel, die einen Verweis auf einen "Client", "Mitarbeiter" und einen "Service" benötigt, die jeweils eigene Aggregate sind, anstatt sie über den Termin zu laden und zu behalten Es ist sinnvoll, einen Verweis auf sie über ihre ID zu speichern, da dies das einzige Ding ist, das von der Domäne – rtlayzell