2012-03-13 4 views
2

状況:私は '永続性レイヤー'としてLinqToSql(無関係と見なすことができます)を使用しており、問題のあるビジネス関連のロジックがどこに行くべきかに関するアーキテクチャ上の懸念を解決しようとしています。永続性の前にリレーションシップ作成を必要とするエンティティ挿入のために私のコードはどこにあるべきですか?

シナリオ:アプリケーションのユーザーが新しい注文を作成します。彼らがそうするとき、プロダクトキーの集まりはその注文と関連付けられる必要があります。

私の最初の試みは、このジャズのすべてをOrderServiceクラスに入れることでした。

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); 
} 

が意図したとおり、これは動作しないという事実を無視(プロダクトキーが実際に順番に関連付けされることはありません)、私はと感じて:その後、私は部分的なメソッドを使用して、私のDataContextのでそれを組み込むことを試みこれは私のビジネスドメインから論理をはずし、それを私の「永続性レイヤー」にプッシュします。私はOrderServiceクラスに入れることも考えましたが、ドメインエンティティからロジックを取り除き、トランザクションスクリプトを作成しただけであると感じました。 Order Factoryを導入するだけで、問題が回避されます。データとロジックが再び分離されます。

貧血のドメインモデルを避け、栄光のあるデータ構造の他に何かをして欲しいと思っても、このロジックを私のドメインモデルに統合する適切な方法はありますか?

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"); 
     } 
    } 
} 

ので、次のようになり、コードの消費:

私はまだ出ている最善の解決策は、Orderクラスにロジックを入れて、それが検証フックで行われたことを確認することです

// The Unit of Work 
using (var context = new MyDataContext()) 
{ 
    ... 
    order.AssociateWithProductKeys(context); 
    context.Orders.InsertOnSubmit(order); 
    context.SubmitChanges(); 
} 

==もはや更新LinqToSQL(およびWebフォーム)を使用しているとき、私は、コマンド/クエリパターンを採用している2012年3月29日==

とLinqToSqlによって作成されたエンティティを使用私のデータストアへのマッピング以外のものとしてのDataContext。すべての私のルールと、コマンドオブジェクトに入るものは、アプリケーションの真の核となっています。

+0

私は何かを理解していません。どの層、ロジック、またはデータが、永続化する前に注文に関連付けるためにDB内の製品を見つけようとしますか?注文に既に関連する商品が含まれていてはなりませんか?私はクライアントが注文と製品を関連づけ、ロジッククラスはルール違反を検証し、DALは単にドメインエンティティをDBエンティティ/テーブルにマッピングし、それを永続させると思います。いいえ? –

+0

クライアントは、プロダクトキーをオーダーに関連付ける責任を負いません。クライアントが注文を作成するときに、必要なキーの数を指定します。これらのキーを割り当てるのはシステムです。それは問題の中心です:その割り当て論理はどこに行き、その本質は何か:ビジネスかそうでなければ何ですか? – Merritt

+0

ああ、あなたは鍵の割り当てについて話しています。はい。したがって、クライアントはプロダクトキーの数を選択しますが、実際のプロダクトは選択しません。クライアントが注文のためにプロダクトを選んだ場合、そのキーは既にエンティティ内に存在するはずです。それはクライアントが見ることができないはずですが、にもかかわらず存在するはずです。 –

答えて

0

クライアントは、注文をビジネスロジックレイヤー(BLL)に渡します。 BLLはDALメソッドを呼び出してn個のプロダクトキーを取得します。 DALはロジックを実装せず、単にn個のキーを取得します。その後、BLLはDALが提供したものに反応する。十分なキーがある場合、BLLはそれらのキーをオーダーに関連づけて返します。十分なキーがない場合、BLLはキーをオーダーに関連付けず、例外をスローします。次に、クライアントは、論理層が何を返すかに基づいて、適切なUIメッセージをユーザに提供する。

私はDALに論理が存在してはならないというあなた自身の評価に同意します。これは、異なるユースケースのシナリオからDALメソッドを再利用できる可能性があることを意味し、ビジネスルールが変更され、新しいユースケースが出現する可能性があるため、DALが何かを決定することは望ましくありません。

これは役に立ちますか?

+0

あなたは私が述べたことを、別の用語で述べています。私はあなたが何をしているのかわからない。 – Merritt

0

私は全くそれが無関係な考えていない(無関係と考えられる)

LinqToSqlを使用しています。

LINQ-to-SQLが「本当の」ORMであるかどうかの議論を無視して、私はすべてのORM(および特定のLINQ-to-SQL)が使い方が非常に規範的であることを発見しました。好みのパターンに固執すれば、すべてが簡単です。選択したコードを構造化し、苦痛の世界に向かう危険性があります。

この例では、LINQ-to-SQLは、データアクセスとロジック(密結合)の両方を含む場合に最適です。非常に小さなプロジェクト以外のものがあり、デバッグの悪夢につながると、これはひどい習慣ですが、データアクセスとロジックを分割しようとすると、一般的な問題が発生します。

DataContextは、作業単位として使用される短命オブジェクトである必要があります。このアプローチは、LINQ-to-SQLが使用する「接続された/分離された」モデルのためうまく動作しません。私の意見では、恐ろしい、「シリアライゼーションによるデタッチ」ハックを提案する数多くのウェブサイトがあります。

さらに、ORMモデルは、フル機能のカプセル化オブジェクトではなく、データオブジェクトに適しています。 DataContextは、オブジェクト間の関係を維持する必要があります。そのため、オブジェクト自身の責任を負うことは、しばしば後の頭痛につながります。

私はLINQ-to-SQLを楽しんでいて、多くのプロジェクトでそれを使用していましたが、すばらしいパターンはお勧めできません。データレベルのオブジェクト指向パターンに対して積極的にお勧めします。あなたが知っているものを忘れて、代わりにデータレイヤーを維持しやすいものを書くようにしてください。私の経験では、厳密なデザインルールに基づいてロジックとデータアクセスを分離することは、後でこのツールキットで重大な問題につながります。

+0

私はこの回答が私を悩ます(私の前のコメントを削除しました)がどれほどであるかについては気をつけていますが、代わりにLinToSqlを使用する建築的な影響に関するあなたの意見を述べてくれてありがとうと思います。しかし、それは本当に私の質問に直接取り組んでいないのですか?それが役立つ場合は、リポジトリパターンを使用しているDataContextの代わりにふりをする。あなたのコードはどのように見えるでしょうか? – Merritt

+0

なぜ私が悪化したのかというと、私の質問はビジネスオブジェクトを活性化させることであり、本当に永続性とはほとんど関係がありませんでした。私は自分自身がAggregateRootXServiceを書いて、そこにすべてのロジックを入れているのを見て、ただ気分が悪いだけです。 – Merritt

+0

@メリット私はあなたの不満を理解しています。質問に答えるのではなく単なるコメントではありません。私はいくつかのフィードバックを与えると思ったいくつかの答えを持っていた。あなたの「あなたのコードはどこにあるべきですか」という質問への私の答えは、可能な限り短く、「新しいDataContext()のすぐ隣に」あります。より長い答えは、LINQ-to-SQLを使用する場合、コードの使いやすさには2次的な考慮事項があります。 –

関連する問題