Fallstricke des domänengesteuerten Designs mit Entity Framework


11

Viele Tutorials zu DDD, die ich studiert habe, befassen sich hauptsächlich mit Theorie. Sie alle haben rudimentäre Codebeispiele (Pluralsight und ähnliches).

Im Internet gibt es auch Versuche einiger Leute, Tutorials zu DDD mit EF zu erstellen. Wenn Sie sie nur kurz studieren, bemerken Sie schnell, dass sie sich stark voneinander unterscheiden. Einige Leute empfehlen, die App auf ein Minimum zu beschränken und die Einführung zusätzlicher Ebenen, z. B. eines Repositorys über EF , zu vermeiden. Andere generieren entschieden zusätzliche Ebenen und verletzen häufig sogar SRP, indem sie DbContextin Aggregate Roots injizieren .

Ich entschuldige mich schrecklich, wenn ich eine meinungsbasierte Frage stelle, aber ...

Wenn es um die Praxis geht - Entity Framework ist eines der leistungsstärksten und am weitesten verbreiteten ORMs. Sie werden leider keinen umfassenden Kurs finden, der DDD behandelt.


Wichtige Aspekte:

  • Entity Framework bringt UoW & Repository ( DbSet) sofort einsatzbereit

  • Mit EF haben Ihre Modelle Navigationseigenschaften

  • mit EF alle Modelle sind immer verfügbar ab DbContext(sie sind als dargestellt DbSet)

Tücken:

  • Sie können nicht garantieren, dass Ihre untergeordneten Modelle nur über Aggregate Root betroffen sind. Ihre Modelle verfügen über Navigationseigenschaften und können geändert und aufgerufen werdendbContext.SaveChanges()

  • Mit DbContextkönnen Sie auf jedes Modell zugreifen und so Aggregate Root umgehen

  • Sie können den Zugriff auf die untergeordneten Elemente des Stammobjekts über die Methode ModelBuilderin einschränken OnModelCreating, indem Sie sie als Felder markieren. Ich glaube immer noch nicht, dass dies der richtige Weg für DDD ist. Außerdem ist es schwierig zu bewerten, zu welchen Abenteuern dies in Zukunft führen kann ( ziemlich skeptisch) )

Konflikte:

  • Ohne die Implementierung einer weiteren Repository-Schicht, die Aggregate zurückgibt, können wir die oben genannten Fallstricke nicht einmal teilweise beheben

  • Durch die Implementierung einer zusätzlichen Repository-Schicht ignorieren wir die integrierten Funktionen von EF (jedes DbSetist bereits ein Repo) und komplizieren die App übermäßig


Meine Schlussfolgerung:

Bitte entschuldigen Sie meine Unwissenheit, aber basierend auf den obigen Informationen - entweder ist das Entity Framework nicht für domänengesteuertes Design geeignet oder das domänengesteuerte Design ist ein unvollständiger und veralteter Ansatz.

Ich vermute, dass jeder der Ansätze seine Vorzüge hat, aber ich bin jetzt völlig verloren und habe nicht die geringste Ahnung, wie EF mit DDD in Einklang gebracht werden kann.


Wenn ich falsch liege - könnte jemand zumindest eine einfache Anleitung (oder sogar anständige Codebeispiele) für die Vorgehensweise bei DDD mit EF angeben?


Ich habe hier Schritte detailliert beschrieben , um zu verstehen, wie EF funktioniert. Diese Schritte behandeln jedoch nicht das Problem des Zugriffs auf Kinder per Navi. Eigenschaften oder von DbSets aus DbContext.
Alex Herman

Antworten:


8

DDD und EF haben wenig bis gar nichts miteinander zu tun.

DDD ist ein Modellierungskonzept. Es bedeutet, über die Domäne und die Geschäftsanforderungen nachzudenken und diese zu modellieren. Insbesondere im Kontext der Objektorientierung bedeutet dies, ein Design zu erstellen, das die Geschäftsfunktionen und -fähigkeiten widerspiegelt.

EF ist eine Persistenztechnologie. Es befasst sich hauptsächlich mit Daten und Datenbankeinträgen.

Diese beiden sind scharf geschieden. Ein DDD-Design kann EF in irgendeiner Form unter der Haube verwenden, aber die beiden sollten nicht auf andere Weise interagieren.

Einige Interpretationen von Domain-Driven Design befürworten tatsächlich die Datenmodellierung, und ich denke, darum geht es in Ihrer Frage. In dieser Interpretation sind "Entitäten" und "Wertobjekte" im Wesentlichen nur funktionslose Dateninhaber, und das Design befasst sich damit, welche Eigenschaften diese haben und welche Beziehung sie zueinander haben. In diesem Zusammenhang kann DDD vs. EF auftreten.

Diese Interpretation ist jedoch fehlerhaft, und ich würde dringend empfehlen, sie insgesamt zu ignorieren.

Fazit : DDD und EF schließen sich nicht gegenseitig aus, sie sind für einander eigentlich irrelevant, solange Sie eine ordnungsgemäße Objektmodellierung und keine Datenmodellierung durchführen. DDD-Objekte sollten in keiner Form EF-Artefakte sein. DDD-Entitäten sollten beispielsweise keine EF- "Entitäten" sein. In einigen geschäftsrelevanten Funktionen verwendet ein DDD-Design möglicherweise EF mit einigen verwandten Datenobjekten. Diese sollten jedoch immer unter einer geschäftsrelevanten verhaltensorientierten Schnittstelle verborgen sein.


1
EF ist nur eine Zeitersparnis. Bei der Verfolgung von Änderungen und der Persistenz von Aggregaten hilft EF bereits sehr. Leider gibt es derzeit keine Möglichkeit, die Form von Aggregaten auf Konfigurationsebene zu definieren.
Pavel Voronin

6

Behandeln Sie EF als Datenzugriffsbibliothek, die nur geringfügig stärker typisiert ist als ADO.NET. Ich würde nicht empfehlen, Ihre Domain mit EF-Entitätsklassen zu modellieren, genauso wie ich nicht empfehlen würde, die Domain mit Raw-DataSet oder DataTable zu modellieren.

Ich verstehe, dass EF als Abkürzung zwischen Datenbankzugriff und Domänenmodellierung verkauft wird. Dieser Ansatz ist jedoch an sich fehlerhaft, da er zwei weitgehend unabhängige Probleme angeht. Es gab andere Versuche in .NET, eine Klasse dazu zu bringen, einige völlig unabhängige Dinge auszuführen (z. B. .NET Remoting), und sie endeten nicht gut.

Führen Sie die DDD mit POCO-Klassen durch und lassen Sie das Datenbankschema nicht Ihr Design steuern. Halten Sie EF in der Repository- / Persistenzschicht und lassen Sie die EF-Entitäten nicht nach außen lecken.


5

Entity Framework bringt UoW & Repository (DbSet) sofort einsatzbereit

Nein.

Entity Framework-Abstraktionen wurden unter Berücksichtigung von ORM und nicht von DDD erstellt. Die DbSetAbstraktion in jeder Version von Entity Framework ist bei DbContextweitem nicht so einfach wie ein DDD-Repository - ganz zu schweigen davon, dass zig Dinge mehr als ein UnitOfWork verfügbar sind.

Hier ist eine nicht erschöpfende Liste von Elementen in der Zusammenfassung von EF Core 2.1, DbSet<TEntity>die wir in DDD nicht benötigen:

  • Attach(TEntity) und alle seine Geschwister
  • Find(Object[])
  • Update(TEntity) und alle seine Geschwister
  • Implementierung IQueryable

Diese ziehen nicht nur nicht benötigte Abhängigkeiten mit sich, sondern verschleiern auch die Absicht eines Repositorys, das normalerweise ein sehr einfaches Erfassungsverhalten aufweist. Außerdem sind die undichten Abstraktionen eine ständige Versuchung für Entwickler, sich viel zu sehr mit EF zu verbinden, und eine Bedrohung für die Trennung von Bedenken.

Fazit: Sie müssen diese Fette in nette, optimierte Konzepte einwickeln und raten, was bedeutet, dass zusätzliche Klassen eingeführt werden.

Ein relativ gutes Beispiel dafür, was Sie mit EF und DDD tun können (obwohl einige der geäußerten Standpunkte umstritten sind): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

andere generieren entschieden zusätzliche Ebenen und verletzen häufig sogar die SRP, indem sie DbContext in Aggregate Roots einfügen

Ich sehe wirklich keinen Zusammenhang zwischen den beiden Teilen dieses Satzes. Unabhängig von der Vorgehensweise gibt es in DDD eine Funktion namens Application Service, mit der Sie die Arbeitseinheit / das Repository (oder DbContext) bearbeiten können . Nicht in aggregierten Wurzeln.

Während es ein gültiger Ansatz sein könnte, wenn es sich um einen gebildeten Kompromiss handelt, ist der jüngste Anti-Repository-Trend "Entity Framework Minimalism" eine Täuschung. Es macht DDD-Muster für die Reibung verantwortlich, die mit Entity Framework auftritt, wenn es wirklich die EF-Entwickler sind, die nichts unternommen haben, um ihr Framework mit den sofort einsatzbereiten Best Practices kompatibel zu machen. Währenddessen werden sie eng mit diesem Framework verbunden, mit all den Problemen in Bezug auf Codesicherheit und Wartbarkeit, die sich daraus ergeben können.


2

Konflikte:

Ohne die Implementierung einer weiteren Repository-Schicht, die Aggregate zurückgibt, können wir die oben genannten Fallstricke nicht einmal teilweise beheben

Durch die Implementierung einer zusätzlichen Repository-Schicht ignorieren wir die integrierten Funktionen von EF (jedes DbSet ist bereits ein Repo) und komplizieren die App übermäßig

Ich habe einen Ansatz verwendet, bei dem jedes Aggregat seinen eigenen DBContext erhält und genau das abbildet, was für das Aggregat benötigt wird. Ich denke, das wurde auch von Julie Lerman beschrieben.

Dies hat sehr gut funktioniert, reicht jedoch möglicherweise nicht für interessantere Modelle aus, bei denen Sie Ihre Konzepte nicht mit Ihren Entitäten verknüpfen möchten.



Gibt es irgendwelche Vorteile des DBContext Per Aggregate-Ansatzes? Ist dies die Standardmethode zum Implementieren von DDD mit EF?
Alex Herman

Meinte Julie Lerman nicht DbContext pro begrenztem Kontext?
Mvision

0

Ich möchte nur eine mögliche Lösung zur Prüfung mitteilen:

  1. Vermeiden Sie es, direkt auf das EF-Projekt in Service Layer zu verweisen

  2. Erstellen Sie eine zusätzliche Repository-Ebene (verwendet EF-Projekt und gibt Aggregate Root zurück).

  3. Verweisen Sie auf das Projekt Repository Layer in Service Layer

Architektur :

  • Benutzeroberfläche

  • Controller-Schicht

  • Serviceschicht

  • Repository-Schicht

  • Entity Framework

  • Kernprojekt (enthält EF-Modelle)


Die Fallstricke, die ich bei diesem Ansatz sehe:

  • Wenn ein Repository Aggregate Root nicht als EF-Modellbaum zurückgibt (z. B. ein zugeordnetes Objekt zurückgeben), verlieren wir die Fähigkeit von EF, Änderungen zu verfolgen

  • Wenn es sich beim Aggregate Root um ein EF-Modell handelt, sind alle Navigationseigenschaften weiterhin verfügbar , auch wenn wir nicht damit umgehen können DbContext(wir verweisen nicht auf das EF-Projekt in Service Layer).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.