Was ist eine Entität?

Im Zuge meiner Beschäftigung mit CQRS und Event Sourcing habe ich mir wieder die Frage gestellt, was denn eigentlich eine DDD Entität sei?

Nun hab ich endlich für mich eine ganz einfache Definition gefunden: Eine Entität ist ein Dictionary<string,string> mit unwandelbarer Id [1].

Jup. Das isses. Mehr nicht [2].

Den Inhalt einer Entität kann man wandeln, die Id aber nicht. Und der Inhalt einer Entität ist strukturiert. Gerade die Annahme, dass Keys Pfade sein können [2], macht mich zufrieden. Nicht nur “Vorname” oder “Mindestgebot” oder “Lagerplatz” sind also Keys, sondern ebenfalls “Wohnsitz/PLZ” oder “Telefonnummern/3” oder “Positionen/2/Menge” [3].

So ein Dictionary ist ein Dokument, d.h. es ist selbstgenügsam (self-contained). Alles, was dazugehört, steht drin. Was nicht drin steht, gehört zu einer anderen Entität. So einfach ist das.

Was Sie als Daten bei einem Key hinterlegen, ist Ihre Sache. Das kann so umfangreich und strukturiert sein, wie es will. Per definitionem ist das aber keine Entität, weil es eben ein Wert in einer Entität ist. Werte als string [4] und nicht als object zu definieren ist mir deshalb sehr wichtig. Dadurch ist ausgeschlossen, aus einer Entität Objekte zu referenzieren.

Entitäten dürfen allerdings Ids anderer enthalten. Solche Entitätsreferenzen sind ok, weil sie sich auf das wahrhaft Unwandelbare beziehen [5]. Beispiel:

var frau = new Dictionary<string,string>{{$$id, "10"}, {"Vorname", "Eva"}, ...};
var mann = new Dictionary<string,string>{{$$id, "0815"}, {"Vorname", "Adam"}, ...};
frau["partner"] = mann["$$id"];
mann["partner"] = frau["$$id"];

Mit der Definition “Eine Entität ist ein Dictionary<string,string>” ist es nun ganz einfach herauszufinden, ob ein zusammengesetzter Wert eine Entität ist oder nicht. Fragen Sie sich einfach, ob Sie den Wert einem oder mehreren Keys in einer anderen Entität zuweisen würden. Beispiel:


Ist der zusammengesetzte Wert

Person("Vorname": "Peter", "GebDat": "1967-05-12", "Geschlecht": "m")

eine Entität? In manchen Zusammenhängen mag das so sein:

var person = new Dictionary<string,string>{{"$$id", "7654}, {"Vorname", "Peter"}, ...};
var einwohner = new Dictionary<string,string>{{"$$id", "0192"}, {"Person", "7654"}};

In anderen wieder nicht. Dann ist er Teil einer umfassenden Entität, z.B.

var einwohner = new Dictionary<string,string>{...};
einwohner["Person"] = "{\"Vorname\": \"Peter\", \"GebDat\": \"1967-05-12\", \"Geschlecht\": \"m\"}";

oder

einwohner["Person/Vorname"] = "Peter";
einwohner["Person/GebDat"] = "1967-05-12";
einwohner["Person/Geschlecht"] = "m";

Ich denke, das macht die Entscheidung einfacher. Doch auch wenn die mal daneben geht, ist es nicht so schlimm. Entitäten in dieser Form kann man auch leicht refaktorisieren. “Inline entity” und “extract entity” scheinen mir genauso probat wie “inline method” und “extract method”. Also keine Angst vor BDUF!


Außerdem lassen sich Entitäten dieser Form sehr leicht verteilt über Ereignisse denken, z.B.

Zugezogen("$$id": "9384", "Nachname": "Müller", "Straße": "Isestr. 2", ...)
Umgezogen("$$id": "9384", "Straße": "Richterstr. 17", "PLZ": "22085", ...)
Geheiratet("$$id": "9384", "Ehepartner": "0815", "Nachname": "Schmied", ...)
Geheiratet("$$id": "0815", "Ehepartner": "9384", ...)

In jedem Ereignis wird die Entität angegeben und danach nur eine Liste von Keys mit neuen Werten. Der aktuelle Stand einer Entität ergibt sich dann aus dem Summe ihrer Ereignisse.


Endnoten


[1] Ob die Id ein Eintrag mit speziellem Key im Dictionary ist oder separat gehalten wird, ist mir erstmal egal.


[2] Noch einfacher könnte man natürlich sagen, eine Entität sei ein strukturierter Text, z.B. ein Json- oder XML-Dokument. Wird letztlich bei NoSql auch so gemacht. Aber das ist mir grad zu wenig griffig, wenn ich an den Umgang damit im Code denke. Mit einem Dictionary fühle ich mich etwas wohler.


Ein geschachteltes Dokument wie


<Person id="1234">
  <Vorname>Peter</Vorname>
  <Anschrift>
   <PLZ>22085</PLZ>
  </Anschrift>
</Person>


sieht mir auch komplizierter aus als eine Liste von Key-Value-Paaren:


$$id:1234
Vorname:Peter
Anschrift/PLZ:22085


Das eine kann in das andere übersetzt werden. Das reicht mir.


[3] Wem da Metadaten fehlen, der kann sie sich gern dazudenken, z.B. “Vorname:string” oder “Positionen/2/Menge:int”. Am Ende ist jedenfalls jeder Wert auf eine Zeichenkette abbildbar.


Wie solche Pfade aussehen, ist hier ebenfalls nicht wichtig. Mit der Syntax, die ich hier benutze, sind Sie ja aber vertraut.


[4] Binärdarstellungen sind nur eine Optimierung. Mit textuellen Repräsentationen von Daten kommen wir weiter. Sie sind ausreichend, bis ein konkreter Use Case etwas anderes fordert.


[5] Allerdings hadere ich hier noch mit mir. Manchmal denke ich, dass Entitäten gar keine Referenzen enthalten sollten. Wenn sie zu anderen in Beziehung stehen, dann nur innerhalb eines Kontextes - und der wird dann von einem Aggregat aufgespannt.


Ein Aggregat ist dann eine Entität, deren Zweck es ist, andere zu verbinden. Es ist ein Beziehungsraum.


So ganz traue ich mich aber noch nicht, das konsequent zu denken. Ich habe es zwar schon einmal in der dotnetpro so beschrieben - doch im Moment bin ich wieder ein wenig im Zweifel… Hm… warum eigentlich? Dazu mach ich mir am besten ein andermal weitere Gedanken.


wallpaper-1019588
[Comic] Das Mietshaus
wallpaper-1019588
TOKYOPOP: Shojo-Lizenzen für das Frühjahrsprogramm 2025
wallpaper-1019588
Der Sommer, in dem Hikaru starb – Neue Details zum Anime bekannt + Trailer
wallpaper-1019588
Bogus Skill – Crunchyroll zeigt Anime im Simulcast