永続性の無知は、標準オブジェクトを取得/永続化する機能です。標準オブジェクトは、特定のビジネス上の問題に焦点を当てたクラスと見なされるため、infrastructure-related logic
は含まれません。 DDDでは、Repository patternを使用してPIを実現します。
Domainをモデル化するためにORMのPOCOオブジェクトを使用しないと仮定すると、Domainオブジェクト特定のO/RMの設計要件(defaultコンストラクタを使用する、またはプロパティをvirtual
)。このようなドメインオブジェクトは考慮されます永続性無視。
しかし、これらのドメインオブジェクトが遅延読み込み、それらのプロパティにはいくつかのロジックが含まれている必要があり、ある時点で関連データが既に読み込まれているかどうかを確認する必要があります。読み込まれていない場合は、適切なRepositoryおよび関連データを要求します。
これらDomain Objectは、どのように永続化されているかを完全に認識していないため、Domainは、基礎となるDALプロバイダーから完全に分離されています、まだそのようなドメインオブジェクトにはInfrastructure-related logic
が含まれているため、違反します[〜#〜] pi [〜#〜]?
同じ問題に遭遇した後、ここに私が実装したソリューションを示します。
ドメイン
public class DomainObject : AggregateRootBase //implements IAggregateRoot
{
private ChildEntity _ChildEntity = null;
public ChildEntity ChildEntity
{
get
{
OnChildEntityRequested();
return _ChildEntity;
}
}
public event EventHandler ChildEntityRequested;
protected void OnChildEntityRequested()
{
if (ChildEntityRequested != null) { ChildEntityRequested(this, new EventArgs()); }
}
public static void SetChildEntity(DomainObject destination, ChildEntity child)
{
//To set or not to set, that is the question.
destination._ChildEntity = child;
}
}
リポジトリの実装
public class DomainObjectRepository : List<DomainObjectTracker>, IDomainObjectRepository
{
private void Load() //Method called by constructor or other loading mechanism.
{
foreach (DomainObjectDataModel dodm in ORMSystem) //Iterating through each object returned from ORM.
{
DomainObject do = Translate(dodm); //Translate into domain object.
do.ChildEntityRequested += new EventHandler(DomainObject_ChildEntityRequested);
DomainObjectTracker tracker = new DomainObjectTracker(do, dodm.Key);
base.Add(tracker);
}
}
protected void DomainObject_ChildEntityRequested(object sender, EventArgs e)
{
DomainObject source = sender as DomainObject;
//Here, you could check to see if it is null or stale before loading it.
//if (source.ChildEntity == null || IsStale(source.ChildEntity))
DomainObjectTracker tracker = base[IndexOf(source)];
ChildEntity entity = LoadChildEntity(tracker.Key); //Load the child entity from ORM.
DomainObject.SetChildEntity(source, entity);
}
}
私のソリューションを調べた後、「イベントインフラストラクチャ関連のコードを呼び出していないのか、それは確かに私のドメインとは関係がないのか」と考えているかもしれません。それは本当かもしれませんが、PIに関してのみ考えると、ドメインから「こんにちは、この子エンティティにアクセスしようとしています」というメッセージを提供しているだけであることに気付くでしょう。これにより、リポジトリが応答します。「しばらくお待ちください(必要な場合(または新しいもの)は、このdbにありますので、続行する前にお知らせします!)」.
ここにはいくつかの注意点があります。 1つは、集計内のすべての子エンティティに対してイベントが必要であることを意味します。 2つ目は、子エンティティを設定するパブリックな方法を許可しているため、カプセル化が解除されることです。一方で、利点は表現力豊かなコードであり、インフラストラクチャの実装はドメインから簡単に分離でき、ドメインオブジェクトはPIであり、ORMはリポジトリ実装の背後でカプセル化されたままです。
誰かがこの問題を解決するより良い方法を持っているなら、私はすべて目です!
[〜#〜] edit [〜#〜]また、私の回答はPIの解決策を提供しますが、上記のコメントに同意します。 DDDが適切な答えであるかどうかを評価する必要があります。これにより、プロジェクトの維持が容易になり、そうでなければ非常に複雑なプロジェクトが簡素化されますが、コストがかかります(通常、事前の開発時間とチームのトレーニング)。コードを適切に整理し、さまざまなパターンを利用するため)。
その価値のあるORMは、遅延読み込みなどの永続性の懸念でモデルを汚染することはありません。通常、これは、完全にロードされたオブジェクト/コレクションのインターフェースを持つ透過プロキシなどの手法を使用して実現されますが、アクセスされるまでロードを延期します。
ORMがこれを行わない場合は、別のORMを見つけることをお勧めします。
ORMは、モデルの永続性指向バージョンとモデルのドメイン指向バージョンを強制するべきではなく、2つのモデル間でマッピングする必要があります。これは、オブジェクトリレーショナルmapperが行うことです。それが存在する理由のすべてです。
ドメインロジックにORM POCOを使用しない場合は、問題ありません。また、遅延読み込みやキャッシュなど、それらに付属するすべてのものを放棄します。これらは、ドメインの一部として(必要な場合)考慮する必要がある機能になるか、下位層のORMによって提供されると想定します。
もう1つの課題は、データをORM POCOからドメインPOCOに往復させる追加の手順です。これは、Automapperなどのツールを使用して実行できますが、オブジェクトを更新するときにORMに強制的に取得させる必要がある場合などの問題を引き起こします。 ORMの実装方法に応じて、更新できます。
100%の純度を要求することで、実際にどれだけの利益を得ていますか? PIに違反していないことは本当に重要ですか?