web-dev-qa-db-ja.com

Entity Frameworkによるドメイン駆動設計の落とし穴

私が研究したDDDに関するチュートリアルの多くは、主に理論をカバーしています。これらにはすべて、基本的なコード例(Pluralsightなど)があります。

Webでは、EFを使用したDDDをカバーするチュートリアルを作成しようとする試みも数人います。それらをほんの少しだけ調べ始めると、それらは互いに大きく異なることにすぐに気付くでしょう。アプリを最小限に保つことをお勧めする人もいますEFの上にリポジトリなどの追加レイヤーを導入しないようにするため、他の人は明らかに追加レイヤーを生成し、集約ルートにDbContextを注入してSRPに違反することさえあります。

意見ベースの質問をしている場合、私はひどくお詫びしますが...

実践となると-Entity Frameworkは、最も強力で広く使用されているORMの1つです。残念ながら、DDDに関する包括的なコースは見つかりません。


重要な側面:

  • Entity Frameworkは、UoWとリポジトリ(DbSet)をすぐに使用できるようにします

  • eFでは、モデルにナビゲーションプロパティがあります

  • eFでは、すべてのモデルが常にavailable off DbContext(モデルはDbSetとして表されます)

落とし穴:

  • あなたできません子モデルが集約ルートを介してのみ影響を受けることを保証します-モデルにはナビゲーションプロパティがあり、それらを変更してdbContext.SaveChanges()を呼び出すことができます

  • DbContextを使用すると、すべてのモデルにアクセスできるため、回避集合ルート

  • ModelBuilderメソッドでOnModelCreatingを介してルートオブジェクトの子へのアクセスを制限できますフィールドとしてマークすることにより-それでも正しい方法であるとは思いませんDDDに加えて、これが将来どのような冒険につながるかを評価するのは難しい(かなり懐疑的

矛盾:

  • 実装せずに Aggregateを返すリポジトリの別のレイヤーでは、上記の落とし穴を部分的に解決することもできません

  • 実装することによりリポジトリの追加レイヤー。EFの組み込み機能を無視し(DbSetはすべてすでにレポです)、アプリを複雑にしています。


私の結論:

私の無知を許してください、しかし上記の情報に基づいてください-それはエンティティフレームワーク十分ではありませんまたはドメイン駆動設計のいずれかであるか、またはドメイン駆動設計は不完全および- 廃止アプローチ。

それぞれのアプローチにはメリットがあると思いますが、今は完全に道に迷っており、EFとDDDをどのように調整するかについては少しも考えていません。


私が間違っている場合-EFでDDDを実行する方法の簡単な一連の手順を詳細に説明できますか(または適切なコード例を提供できますか)。

11
Alex Herman

DDDとEFは、互いにほとんどまたはまったく関係がありません。

DDDはモデリングの概念です。それは、ドメイン、ビジネス要件について考え、それらをモデル化することを意味します。特にオブジェクト指向のコンテキストでは、ビジネスの機能と機能を反映したデザインを作成することを意味します。

EFは永続化テクノロジです。主にデータとデータベースのレコードに関係しています。

これら二つは、はっきりと離婚しています。 DDDの設計では、内部でなんらかの形でEFを使用できますが、この2つは他の方法で相互作用してはなりません。

ドメイン駆動設計のいくつかの解釈は、実際にデータモデリングを提唱していますが、これがあなたの質問に関するものだと思います。この解釈では、「エンティティ」と「値オブジェクト」は基本的に機能のないデータホルダーのみであり、設計はそれらがどのようなプロパティを保持し、相互にどのような関係を持っているかに関係します。このコンテキストでは、DDDとEFの比較が考えられます。

ただし、この解釈には欠陥があり、完全に無視することを強くお勧めします。

結論として:DDDとEFは相互に排他的ではなく、データモデリングではなく適切なオブジェクトモデリングを実行している限り、実際には互いに無関係です。 DDDオブジェクトは、EFアーティファクトであってはなりません。 DDDエンティティは、たとえばnotはEF "エンティティ"である必要があります。一部のビジネス関連機能の内部では、DDD設計はEFをいくつかの関連するデータオブジェクトと共に使用する場合がありますが、それらは常にビジネス関連の動作指向のインターフェースの下に隠されている必要があります。

8

EFをそれが何であるか、つまり生のADO.NETよりもわずかに強く型付けされているデータアクセスライブラリに対応させます。生のDataSetまたはDataTableを使用してドメインをモデル化するのと同じように、EFエンティティクラスを使用してドメインをモデル化することはお勧めしません。

私はEFがデータベースアクセスとドメインモデリングの間のショートカットとして販売されていることを理解していますが、このアプローチは2つの大きく関連しない問題に対処するため、本質的に欠陥があります。 .NETには、クラスに完全に関連のない処理(.NET Remotingなど)を実行させる他の試みがありましたが、うまくいきませんでした。

POCOクラスを使用してDDDを実行し、データベーススキーマに設計を推進させないでください。 EFをリポジトリ/永続化レイヤー内に保持し、EFエンティティが外部に漏洩しないようにします。

6
KolA

Entity Frameworkは、UoW&リポジトリ(DbSet)をすぐに使用できるようにします

番号。

Entity Frameworkの抽象化は、DDDではなくORMを念頭に置いて構築されました。 Entity FrameworkのどのバージョンのDbSet抽象化も、DDDリポジトリの単純さにはほど遠いです。言うまでもなく、UnitOfWorkよりも多くのことを公開するDbContextは言うまでもありません。

DDDで必要のない、EF Core 2.1の抽象_DbSet<TEntity>_の要素の完全ではないリストを次に示します。

  • Attach(TEntity)およびそのすべての兄弟
  • Find(Object[])
  • Update(TEntity)およびそのすべての兄弟
  • IQueryableの実装

それらとの不要な依存関係に沿ってドラッグすることに加えて、これらは通常非常に単純なコレクション動作を公開するリポジトリの意図を覆い隠します。さらに、リークの多い抽象化は、開発者がEFに過度に結合しようとする絶え間ない誘惑であり、懸念の分離への脅威です。

結論:これらの脂肪をニースの合理化された概念にラップし、何を推測するか、つまり追加のクラスを導入する必要があります。

EFとDDDでできることの比較的健全な例(ただし、いくつかの見解は議論の余地があります): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and- entity-framework /

他の人は明らかに追加のレイヤーを生成し、多くの場合、DbContextを集約ルートに挿入することでSRPに違反します

この文の2つの部分の間の関係は本当にわかりません。アプローチに関係なく、DDDにはアプリケーションサービスと呼ばれるものがあり、そこで作業ユニット/リポジトリ(またはDbContext)を操作します。集計ルートにはありません。

教育を受けたトレードオフである場合、これは有効なアプローチである可能性がありますが、最近の反リポジトリである「エンティティフレームワークミニマリズム」の傾向は妄想的です。フレームワークをそのまますぐにベストプラクティスに準拠させるために何もしなかったのがEF作成者である場合、Entity Frameworkで発生する摩擦のDDDパターンのせいです。コードの安全性と保守性の点で問題が発生し、フレームワークと密接に結びついています。

5
guillaume31

矛盾:

aggregateを返すリポジトリの別のレイヤーを実装しないと、上記の落とし穴を部分的に解決することさえできません

リポジトリーの追加レイヤーを実装することで、EFの組み込み機能を無視し(すべてのDbSetはすでにリポジトリーです)、アプリを過度に複雑にします

私は、すべての集合体が独自のDBContextを取得し、集合体に必要なものだけをマッピングするアプローチを使用しました。これはジュリー・ラーマンにも説明されていると思います。

これは非常にうまくいきましたが、コンセプトをエンティティにリンクしたくないより興味深いモデルには不十分かもしれません。

2
mvg

考えられる解決策を共有したいだけです。

  1. サービスレイヤーでEFプロジェクトを直接参照しないようにする

  2. 追加のリポジトリレイヤーを作成します(EFプロジェクトを使用して集約ルートを返します)

  3. サービスレイヤープロジェクトのリポジトリレイヤーを参照する

アーキテクチャ

  • UI

  • コントローラー層

  • サービス層

  • リポジトリ層

  • エンティティフレームワーク

  • コアプロジェクト(EFモデルを含む)


このアプローチで私が見る落とし穴:

  • リポジトリがAggregate RootをEFモデルツリーとして返さない場合(たとえば、マップされたオブジェクトを返す)-EFが変更を追跡する機能を失います

  • 集約ルートがEFモデルである場合、DbContextを処理できなくても、ナビゲーションプロパティのすべてまだ使用可能です(サービスレイヤーではEFプロジェクトを参照しません) )

0
Alex Herman