EF 4.2コードファーストとDDDデザインの問題

私はEF 4.2(またはEF 4.1)コードでDDD開発を最初にやろうとすると、いくつかの懸念があります。私はいくつかの広範な研究を行ってきたが、私の具体的な懸念に対する具体的な回答は出ていない。ここに私の懸念があります:

  1. ドメインは持続層について知ることはできません。言い換えれば、ドメインはEFから完全に分離されています。ただし、データベースにデータを保持するには、各エンティティをEFコンテキストにアタッチまたは追加する必要があります。ファクトリを使用して集約ルートのインスタンスを作成することになっているので、ファクトリは作成されたエンティティをEFコンテキストに登録する可能性があります。これは、ファクトリがドメインの一部であり永続性レイヤの一部ではないため、DDDルールに違反しているように見えます。エンティティの作成と登録については、エンティティを正しく保持するために、どのように作成する必要がありますか?

  2. 集合エンティティを子エンティティを作成するエンティティにする必要がありますか?つまり、 Organization があり、 Organization Employee エンティティのコレクションがある場合、 CreateEmployee AddEmployee などのメソッドを持っていますか? Employee エンティティを作成すると、 Organization 集合ルートが Employee エンティティをすべて所有していることに留意してください。

  3. 最初にEFコードを操作する場合、各エンティティのID列(データベース内のID列の形式)のIDは自動的に処理されるため、通常はユーザーコードで変更する必要はありません。 DDDはドメインが永続性の無知とは別であると述べているため、IDを公開するのは奇妙なことです。これは、ドメインが新しく作成されたエンティティに一意のIDを割り当てることを処理する必要があるからです。エンティティのIDプロパティを公開することを心配すべきですか?

私はこれらがオープンなデザインの質問であることを理解していますが、永続性レイヤーとしてEFを使用している間はDDDデザインパターンに固執しようとしています。

前もって感謝します!

13
これらは良い質問です!答えを勉強して楽しみにしています!
追加された 著者 n8wrl,

2 答え

1:私はEFに精通しているわけではありませんが、コードファースト/規約に基づいたマッピング方法を使用しているので、POCOをgetterとsetterにマップするのは難しくないと思います( " DbContext <他のプロジェクトで DbSet のプロパティ "クラスを使用している場合はそれほど難しくありません)。私はPOCOが集約ルートであるとは考えていません。むしろそれらは「あなたが保持したい集約内の状態」を表します。以下の例:

// This is what gets persisted
public class TrainStationState {
  public Guid Id { get; set; }
  public string FullName { get; set; }
  public double Latitude { get; set; }
  public double Longitude { get; set; }

 //... more state here
}

// This is what you work with
public class TrainStation : IExpose<trainStationState> { 
  TrainStationState _state;

  public TrainStation(TrainStationState state) {
    _state = state;
    //You can also copy into member variables
    //the state that's required to make this
    //object work (think memento pattern).
    //Alternatively you could have a parameter-less
    //constructor and an explicit method
    //to restore/install state.
  }

  TrainStationState IExpose.GetState() {
    return _state;
    //Again, nothing stopping you from
    //assembling this "state object"
    //manually.
  }

  public void IncludeInRoute(TrainRoute route) {
    route.AddStation(_state.Id, _state.Latitude, _state.Longitude);
  }
}

現在、集約ライフサイクルに関して、2つの主なシナリオがあります。

  1. 新しい集約を作成する:必要に応じて、ファクトリ、ファクトリメソッド、ビルダー、コンストラクタなどを使用できます。集約を永続化し、その状態を照会して永続化する必要がある場合(通常、このコードはドメイン内にはなく、かなり一般的です)。
  2. 既存の集計を取得する:必要に応じて、リポジトリ、DAOなどを使用できます。永続ストレージから取得するものは、状態のPOCOであることを理解しておく必要があります。これは、元の集約に注入する(またはプライベートメンバーを作成するために使用する)必要があります。これはすべてリポジトリ/ DAOファサードの背後で起こります。この一般的な行動であなたのコールサイトを混乱させないでください。

2:いくつかのことが思い浮かぶ。ここにリストがあります:

  1. 集約ルートは一貫性の境界です。組織と従業員の間でどのような一貫性の要件がありますか?
  2. 組織は、組織の状態を変更することなく、従業員の工場として行動することができます。
  3. 「所有権」は、集約に関するものではありません。
  4. 集約ルートには、一般的に、集約内のエンティティを作成するメソッドがあります。根は集約内の一貫性を強制するため、これは意味があります。

3:外部から識別子を割り当て、それを乗り越えて移動します。それは彼らを暴露することを暗に意味するものではありませんが(POCOの州でのみ)

24
追加された
Yves、私はこのアプローチが気に入っていると思いますが、ナビゲーションプロパティを含めるようにコードを拡張できますか?そこに使用しているパターンの詳細情報へのリンクはありますか?
追加された 著者 saille,
貧血ドメインモデルはどうですか?あなたがここでやっていることは、POCOを貧弱にしてトランザクションスクリプトに変換することです...「メンバー変数にコピーすることもできます」はさらに悪いことです。この無邪気に見えるコメントは、本当に意味します。私は、Entity Frameworkが自動的にやるべきことを手によって行います。
追加された 著者 Bartłomiej Szypelow,
@saille私は他の人が以前この手法を使っていたと確信しています。だから私はこの特別なことは考えていない。 Wrtナビゲーション(レイ・ロード)プロパティーは、そうしないでください。アグリゲートをモデリングする場合、伝統的な意味でのナビゲーションの理由はありません。私はdomaindrivendesign.orgのVaughnの集計デザインのホワイトペーパーをご覧になることをお勧めします。
追加された 著者 Yves Reynhout,
@アルベルト:絶対に考えていない。メメントはエンティティと出会う?
追加された 著者 Yves Reynhout,
これらのエンティティがドメインオブジェクトであることを欺くことをやめることは、この技術では何の改善も得られません。あなたがEFで永続性の無知を達成できると思うなら、私のゲストにこのアドバイスを無視させてください。明らかにそれはあなたのためではありません。集約が状態オブジェクトに対するトランザクションスクリプトであると考えるなら、あなたは本当にポイントIMOを得ていません。 EFを使って疎結合モデルを設計することはできますが、最終的にどこで終わるのかはめったにありません。状態をプライベートにすること、プリミティブを値のオブジェクト/エンティティに変換すること、状態を書込みの便利な状態にすることは、これ
追加された 著者 Yves Reynhout,
すべてについてです。あなたは、その部門のNHibernateでもっと良いです、IMO。しかし、あなたがEFを扱いたいのであれば(元の声明を書く時に)、少なくとも、あなたは何を得るのかを知っています。その地点でゲッターを振りかざすのではなく、その時点で明示的に明示的にすることが良いでしょう。私はより多くの自由が続くと主張したい。しかし、あなたのコメントのトーンを考えれば、私たちはこれに目を向けることは決してありません。
追加された 著者 Yves Reynhout,
完璧!それは私が苦労していることの素晴らしい説明です。すべての私の研究では、ドメインオブジェクトの状態が分割されているこの種の解決策を見たことはありません。私はこの新しいデザインと私のすべてのポイントを打つために感謝の周りに混乱します。もしできれば+2。
追加された 著者 Alex Jorgenson,
@ YvesReynhoutにはこのパターンの名前がありますか?私はそれを "Toreador"と呼んでいますが、すでに名前が付けられていると思います。
追加された 著者 ZioBrando,
  1. EF-DDDとの互換性の主な問題は、プライベートプロパティを維持する方法であると思われます。 Yvesによって提案された解決策は、場合によってはEFパワーの欠如に対する回避策であるように思われる。たとえば、DDDではFluent APIを使用して状態プロパティを公開する必要はありません。 私は.edmxファイルでのマッピングだけがドメインエンティティを純粋なままにすることができることを発見しました。 EFに依存する属性をpublcまたは追加するように強制するものではありません。

  2. エンティティは常に集約ルートによって作成される必要があります。 Udi Dahanの素晴らしい投稿をご覧ください: http:// www。 udidahan.com/2009/06/29/dont-create-aggregate-roots/ いくつかの集約を読み込んでそこからエンティティを作成することも、エンティティをEFコンテキストに関連付けるという問題を解決します。その場合、手動で何かを付ける必要はありません。リポジトリからロードされた集約がすでに接続されており、新しいエンティティへの参照があるため、自動的に接続されます。リポジトリインタフェースはドメインに属しますが、リポジトリ実装はインフラストラクチャに属し、EF、コンテキスト、接続などを認識しています。

  3. 永続ストアの実装の詳細として、自動生成されたIDを処理する傾向があります。これは、ドメインエンティティが考慮する必要があるが公開されるべきではありません。だから私は、自動生成された列にいくつかの別の、IDのカードIDやPassportのPersonクラスのようなドメインにとって意味のある公開IDにマップされているプラ​​イベートIDプロパティを持っています。そのような意味のあるデータがない場合は、データベース呼び出しを必要とせずに(ほとんど)一意の識別子を作成するという素晴らしい機能を持つGuid型を使用します。 このパターンでは、私はこれらのGuid/MeaningfulIDを使用してリポジトリから集約をロードしますが、自動生成されたIDはデータベースによって内部的に使用され、少し速く結合されます(Guidはそれには不向きです)。

2
追加された