2

状況:「永続層」に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によって作成されたエンティティをデータストアへのマッピング以外のものとして使用しなくなりました。私のすべてのルールとコマンドオブジェクトに入らないものは、ある意味でアプリケーションの真のコアになります。

4

2 に答える 2

0

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

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

それは役に立ちますか?

于 2012-03-14T01:05:21.957 に答える
0

私はLinqToSqlを使用しています(無関係と見なされる可能性があります)

私はそれをまったく無関係とは考えません。

LINQ-to-SQL が「実際の」ORM であるかどうかの議論は無視して、すべての ORM (および特定の LINQ-to-SQL) は、使用してほしいという点で非常に規範的であることがわかります。彼らの好みのパターンに固執すれば、すべてが簡単です. 選択したとおりにコードを構成すると、苦痛の世界に向かう危険があります。

この場合、LINQ-to-SQL は、データ アクセスとロジックの両方 (密結合) で構成されている場合に最適に機能します。これは、非常に小規模なプロジェクト以外の場合は悪夢のようなデバッグにつながる恐ろしい慣行ですが、データ アクセスとロジックを分離しようとすると、いくつかの一般的な問題が発生します。

Microsoft の推奨事項は、 aDataContextは作業単位に使用される存続期間の短いオブジェクトにすることです。このアプローチは、LINQ-to-SQL が使用する「アタッチ」/「デタッチ」モデルのため、うまく機能しません。私の意見では、「シリアライゼーションによるデタッチ」ハックを提案している Web サイトが多数あります。

さらに、ORM モデルは、完全な機能を備えたカプセル化されたオブジェクトではなく、データ オブジェクトに適しています。オブジェクト間のDataContext関係を維持する必要があるため、オブジェクト自体に責任を負わせることは、後で頭痛の種になることがよくあります。

私は LINQ-to-SQL を楽しんでおり、多くのプロジェクトで使用してきましたが、優れたパターンを推奨することはできず、データ レベルでのオブジェクト指向パターンを積極的に推奨することはできません。知っていることは忘れて、代わりに、管理しやすいデータ レイヤーを作成してみてください。私の経験では、厳密なデザイン ルールに基づいてロジックとデータ アクセスを分離すると、後でこのツールキットで重大な問題が発生します。

于 2012-03-14T04:46:53.737 に答える