it-swarm.com.de

Fallstricke des domänengesteuerten Designs mit Entity Framework

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 minimal zu halten und m zu vermeiden, dass zusätzliche Ebenen, z. B. Repository, über EF eingeführt werden, andere generieren entschieden zusätzliche Ebenen und verletzen häufig sogar die SRP, indem sie DbContext in Aggregate Roots einfügen .

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) aus der Box

  • mit EF haben Ihre Modelle Navigationseigenschaften

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

Tücken:

  • sie können nicht garantieren, dass Ihre untergeordneten Modelle nur über Aggregate Root betroffen sind - Ihre Modelle haben Navigationseigenschaften und es ist möglich, sie zu ändern und dbContext.SaveChanges() aufzurufen

  • mit DbContext können Sie auf jedes Modell zugreifen, also mgehen Aggregate Root

  • sie können den Zugriff auf die untergeordneten Elemente des Stammobjekts über die Methode ModelBuilder in OnModelCreating einschränken indem Sie sie als Felder markieren - Ich glaube immer noch nicht, dass dies der richtige Weg ist DDD plus es ist schwer zu bewerten, zu welchen Abenteuern dies in Zukunft führen könnte ( ziemlich skeptisch )

Konflikte:

  • ohne Implementierung Eine weitere Ebene des Repositorys, die Aggregate zurückgibt. Wir können die oben genannten Fallstricke nicht einmal teilweise beheben.

  • durch Implementierung eine zusätzliche Ebene des Repositorys ignorieren wir die integrierten Funktionen von EF (jedes DbSet ist bereits ein Repo) und komplizieren die App übermäßig


Meine Schlussfolgerung:

Bitte entschuldigen Sie meine Unwissenheit, aber basierend auf den obigen Informationen - es ist entweder Entity Framework nicht ausreichend für domänengesteuertes Design oder das domänengesteuerte Design ist ein nvollkommen und - veraltet 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?

11
Alex Herman

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 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 zum Beispiel nicht EF "Entitäten" sein. Innerhalb einer geschäftsrelevanten Funktion verwendet ein DDD-Design möglicherweise EF mit einigen verwandten Datenobjekten. Diese sollten jedoch immer unter einer geschäftsrelevanten verhaltensorientierten Schnittstelle verborgen sein.

8

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, Domain mit Raw-DataSet oder DataTable zu modellieren.

Ich verstehe, dass EF als Abkürzung zwischen Datenbankzugriff und Domänenmodellierung verkauft wird, aber dieser Ansatz ist 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.

6
KolA

Entity Framework bringt UoW & Repository (DbSet) sofort einsatzbereit

Nein.

Entity Framework-Abstraktionen wurden unter Berücksichtigung von ORM und nicht von DDD erstellt. Die Abstraktion DbSet in jeder Version von Entity Framework ist bei weitem nicht so einfach wie ein DDD-Repository - ganz zu schweigen von DbContext, das zig Dinge mehr als eine UnitOfWork verfügbar macht.

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 von 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 an EF zu koppeln, und eine Bedrohung für die Trennung von Bedenken.

Fazit: Sie müssen diese Fette in nette, optimierte Konzepte einwickeln und raten, was das bedeutet, zusätzliche Klassen einzuführen.

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.

5
guillaume31

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 machen die App zu kompliziert

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.

2
mvg

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. geben wir ein zugeordnetes Objekt zurück), verlieren wir die Fähigkeit von EF, Änderungen zu verfolgen

  • wenn das Aggregate Root ein EF-Modell ist - alle Navigationseigenschaften sind noch verfügbar, obwohl wir nicht mit DbContext umgehen können (wir verweisen nicht auf das EF-Projekt in Service Layer )

0
Alex Herman