Sollte ich beim Entwerfen meines Repositorys einen aggregierten Stamm verwenden?

8

Ich habe eine Entität namens Master, die sich aus einer Reihe von Slave-Entitäten zusammensetzt.

Es kann nur einen Master in meiner Datenbank geben, und ich möchte Repositorys abfragen, um den Slave für eine bestimmte ID abzurufen.

Ich habe zunächst ein SlaveRepository erstellt und dieses nach id abgefragt. Das scheint in Ordnung zu sein und funktioniert und andere Entwickler könnten mein Repository verwenden.

Dann dachte ich über aggregierte Wurzeln nach und erstellte ein MasterRepository und gab den Master zurück und machte dann eine Schleife, um die erforderliche Slave-Entität zu erhalten. Das Problem, das ich hier hatte, ist, dass ich, sobald ich dies anderen Entwicklern zur Verfügung stelle, dasselbe tun müsste. Ich habe also eine Methode im MasterRepository namens GetSlaveByID (Zeichenfolgen-ID) und dann könnte ich den Slave direkt abrufen (verbirgt die Schleifenfunktionalität) ).

Sollte mein Repository nun einen Slave zurückgeben, obwohl er als MasterRepository bezeichnet wird? Und was noch wichtiger ist, welcher ist der richtige Weg?

Ich bin in den frühen Stadien des Versuchs, DDD und TDD anzuwenden, daher gibt es wahrscheinlich viele Dinge, über die ich nachdenken muss, bevor ich mich für die richtige Art und Weise entscheide.

JD01
quelle

Antworten:

9

Gemäß Eric Evans Methode des domänengesteuerten Designs sollten Sie Repositorys für nicht aggregierte Roots vermeiden.

Er stellt klar fest:

Nur aggregierte Roots können direkt mit Datenbankabfragen abgerufen werden. Alles andere muss durchquert werden.

Es bedeutet aber auch, dass das Repository für den Stamm alle Anforderungen erfüllen muss. Wenn Sie direkten Zugriff auf Teile des Aggregats benötigen, ist ein Aggregatstammobjekt oder dessen Repository dafür verantwortlich.

Es ist also vollkommen in Ordnung, Methoden wie die folgenden in einem aggregierten Root-Repository zu haben:

Slave GetSlave(string id)

Diese Signatur ist jedoch etwas gefährlich, da Identitäten von Kindern in DDD nur im Kontext eines tatsächlichen Stammobjekts sinnvoll sind und ohne die Wurzel flach sind.

Dies führt uns zu einem besseren und DDD-ähnlichen Ansatz für eine Implementierung in einem Repository:

Slave GetSlaveOfMaster(Master master, string slaveId)
// or
Slave GetSlaveOfMaster(Identity masterId, Identity slaveId)

Aber ich würde diese Methode wahrscheinlich nicht einmal im Repository haben, sondern auf der Master-Entität selbst, um schnell auf die Slaves zuzugreifen. Möglicherweise sogar als Hashtisch ausgesetzt. Das ist der sauberste Ansatz, den ich mir vorstellen kann.

//within the Master entity
Slave GetSlave(Identity slaveId);

Moment mal, das ist nicht das Ende der Geschichte. Wenn Sie Slaves ohne Kenntnis des Masters abrufen müssen, sollten Sie über Ihre Aggregate und Ihr Objektmodell nachdenken. Vielleicht benötigen Sie ein zweites Aggregat, in dem der Slave ein Root ist, und dann sollten Sie ein benutzerdefiniertes Repository für sie haben. Der Slave ist dann nicht nur ein Kind des Masters, sondern eine separate Hierarchie, die wahrscheinlich auch einen Verweis auf einen Master enthält. Es ist wichtig zu wissen, ob ein Slave-Objekt überhaupt ohne Master existieren kann. Wenn dies möglich ist, ist wahrscheinlich ein separates Aggregat der richtige Weg.

Falke
quelle
Vielen Dank für alle Informationen. Ich werde versuchen, Erics Buch zu bekommen, um mehr zu verstehen.
JD01
Sie haben ein zweites Aggregat erwähnt. Ist dies möglich? Wollen Sie damit sagen, dass wir Master als Root-Aggregat und auch Slave im selben Modell haben?
JD01
1
@ JD01: Auf jeden Fall. Sie können ein separates Slave-Aggregat haben, bei dem der Slave die Wurzel ist. Dies entspricht DDD, solange Sie berücksichtigen, dass nur Stammobjekte verfügbar sind. Das bedeutet, dass Sie keine dritte Klasse haben können, die keine Wurzel ist und Teil mehrerer Aggregate ist. Sie können jedoch ein Slave-Aggregat haben, auf das auch als untergeordnetes Element vom Master-Aggregat verwiesen wird. Hier wird es jedoch oft kompliziert (komplexe Beziehungen usw.). Wir versuchen dies hier zu vereinfachen, indem wir nur auf DTO-Objekte verweisen, wenn ein Stamm auf einen anderen Stamm verweisen muss. DTOs sind schreibgeschützt und können nicht geändert werden.
Falcon
1
@ JD01: Diese DTO-Referenzen können natürlich ausgetauscht werden, aber die DTOs selbst sind unveränderlich. Wenn ich mein SlaveDto von einem Master bekomme, kann ich es nicht ändern. Wenn ich es ändern möchte, muss ich sein eigenes Aggregat holen und es dort ändern. Diese DTOs enthalten nur flache Daten, keine Hierarchien und nur das, was erforderlich ist.
Falcon
1
@ JD01: Du solltest dich auch fragen, ob ein Slave ohne Master existieren kann. Wenn dies nicht möglich ist, handelt es sich nicht um eine aggregierte Wurzel. Siehe mein kleines Update.
Falcon
1

Im Allgemeinen sollte es innerhalb der Aggregatgrenze nur ein Repository geben. Und - wie Falcon sagte - Sie könnten zwei separate Aggregate haben, Master und Slave.

Es sieht jedoch so aus, als ob der Hauptfokus in Ihrer Frage auf dem Abrufen von Daten liegt, während es in DDD das Verhalten sein sollte. Aggregatgrenzen sind eine Folge von Verhaltensbeschränkungen (Dinge, die sich gemeinsam ändern und zu erzwingende Invarianten ). Die interne Struktur des Aggregats ist eine Folge dieser Wahl.

Wenn Sie beispielsweise die Dinge entsprechend den Änderungsbedürfnissen richtig gruppieren, müssen Sie nicht unbedingt ein externes Repository aufrufen. In den meisten Fällen sollten sich die erforderlichen Daten für einen Geschäftsvorgang im Aggregat bereits innerhalb der Aggregatgrenzen befinden. Die Notwendigkeit, auf verschiedene Aggregate zuzugreifen, riecht wahrscheinlich nach einer inkonsistenten Grenze.

ZioBrando
quelle