状況:「永続層」にLinqToSql(無関係と見なされる可能性があります)を使用しており、特定の疑わしいビジネス関連のロジックをどこに配置するかについて、アーキテクチャ上の懸念事項を解決しようとしています。
シナリオ:アプリケーションのユーザーが新しい注文を作成します。その場合、プロダクトキーのコレクションをその注文に関連付ける必要があります。
私の最初の試みは、このジャズをすべてOrderServiceクラスに入れることでした。次に、部分的なメソッドを使用して、DataContextに組み込むことを試みました。
partial void InsertOrder(Order instance)
{
var productKeys = this.ProductKeys
.Where(x => x.DeleteDate == null && x.Order == null && !x.Issued)
.Take(instance.NumberOfProductKeys);
if (productKeys.Count() != instance.NumberOfProductKeys)
throw new NotSupportedException("There needs to be more product keys in the database.");
instance.ProductKeys.AddRange(productKeys);
this.ExecuteDynamicInsert(instance);
}
これが意図したとおりに機能しないという事実(プロダクトキーが実際に注文に関連付けられることはありません)を無視すると、これはロジックをビジネスドメインから取り除き、「永続化レイヤー」にプッシュしていると感じます。OrderServiceクラスに入れることも考えましたが、ドメインエンティティからロジックを取り除いて、トランザクションスクリプトを作成しただけだと感じました。Order Factoryを導入すると、問題が回避されます。データとロジックが再び分離されます。
だから私の質問はこれです:貧血のドメインモデルを避け、うまくいけば栄光のデータ構造である以外に何かをするために、このロジックを私のドメインモデルに統合する適切な方法はありますか?
私がこれまでに思いついた最善の解決策は、ロジックをOrderクラスに配置し、検証フックで実行されたことを確認することです。
public partial class Order
{
public void AssociateWithProductKeys(WIIIPDataContext context)
{
var productKeys = context.ProductKeys
.Where(x => x.DeleteDate == null && !x.Issued && x.Order == null && x.ProductType == ProductType)
.Take(NumberOfProductKeys);
if (productKeys.Count() != NumberOfProductKeys)
throw new ValidationException("There needs to be more product keys in the database for product type: " + ProductType.Description);
ProductKeys.AddRange(productKeys);
foreach (ProductKey productKey in ProductKeys)
{
productKey.Issued = true;
}
}
partial void OnValidate(ChangeAction action)
{
if (action == ChangeAction.Insert)
{
if (ProductType.Id == 3 && ProductKeys.Count() != 1)
throw new ValidationException("Attempted to associated more than 1 product key with a CD version.");
if (ProductKeys.Count() != NumberOfProductKeys)
throw new ValidationException("Number of product keys doesn't match expected value");
}
}
}
コードの消費は次のようになります。
// The Unit of Work
using (var context = new MyDataContext())
{
...
order.AssociateWithProductKeys(context);
context.Orders.InsertOnSubmit(order);
context.SubmitChanges();
}
==2012年3月29日更新==
LinqToSQL(およびWebフォーム)を使用するときにコマンド/クエリパターンを採用し、LinqToSqlDataContextによって作成されたエンティティをデータストアへのマッピング以外のものとして使用しなくなりました。私のすべてのルールとコマンドオブジェクトに入らないものは、ある意味でアプリケーションの真のコアになります。