0

Customer、Supplier、および Services を含むデータベースがあります (これは単純化したもので、実際には約 100 のテーブルがあります)

これらのテーブルにアクセスするための新しい Entity Framework ライブラリを開発しています。

顧客には多くのサプライヤーがいます

サプライヤーには多くのサービスがあります

私は従うべきアプローチを決定しようとしています -

A) マッピングを使用して、顧客をサプライヤーに、サプライヤーをサービスに接続します。その後、顧客をロードするたびに、すべてのサプライヤーとそのサービス(および他のテーブルがロードされます)を取得します

B ) エンティティ間のマッピングはありませんが、関連するリポジトリでメソッドを提供します。たとえば、サプライヤーのリポジトリにIEnumerable<Supplier> GetSupplierByCustomerID(int customerID)

EDIT 提案に基づいて上記を IEnumerable に変更しました。

これらは、EF を使用する場合の 2 つの主要なアプローチですか? あなたの観点からは、どちらが優れていると考えられますか。

私が考慮していない別のアプローチはありますか?

4

4 に答える 4

2

私は個人的に多くの簡単な方法を公開します。

マッピングを使用して、顧客をサプライヤーに、サプライヤーをサービスに接続します。顧客をロードするたびに、すべてのサプライヤーとそのサービス (および他のテーブルがロードされます) を取得します。

Nameから顧客の のみを取得する必要がある場合ID、上記のソリューションでは、遅延読み込みを使用しない限り、無駄で重いオブジェクト グラフを読み込む必要がありますが、シリアル化プロセス (3 層アーキテクチャ ?) がある可能性があるため、この場合、遅延読み込みを使用できないため、問題があります。

したがって、たとえば次のように公開できます。

Supplier GetSupplierByID(int supplierID)
IEnumerable<Supplier> GetSuppliersByCustomerID(int customerID)
...

また、公開しないことをお勧めしIQueryableます。可能であれば、IEnumerable代わりに使用してください。すべての意味がよくわかっていない場合の使用の危険性について詳しくは、この記事を参照してください。IQueryable

于 2013-02-13T15:11:28.943 に答える
1

それは私の意見です。それはあなたのビジネス要件に依存するのであなたの場合に適切かどうかはわかりませんが、私は一般的に3番目のオプションを好みます。

  1. すべてのリポジトリIEnumerableはsではなくIQueryablesを返します。これにより、ビジネスロジックを実行する前にすべてのデータベース操作を終了できます。
  2. すべてのリポジトリは、含まれるナビゲーションプロパティを宣言できるオプションのパラメータを持つメソッドを公開します。これにより、必要なナビゲーションエンティティを使用してリポジトリメソッドを呼び出すことができます。
  3. 基本汎用リポジトリを作成し、各リポジトリで継承します。
  4. 作業単位パターンを実装して、コンテキストを共有し、トランザクションを有効にします。

ベースリポジトリからのサンプルメソッド署名(Tエンティティのタイプです):

 IEnumerable<T> Find(Expression<Func<T, bool>> criteria, params Expression<Func<T, object>>[] navigationList)
于 2013-02-13T15:29:30.227 に答える
1

マップしようとしているとき、またはマップしないときは、Aを選択します。ナビゲーションプロパティには多くの利点があり(などCustomer.Supplier)、遅延/熱心な読み込みを制御する方法はたくさんあります。

ナビゲーションプロパティの利点は、linqクエリの記述がはるかに簡単なことです。結合を作成する必要はほとんどありません。

参加あり:

from supp in db.Supliers
join serv in db.Services on supp.SupplierId equals serv.SupplierId
select ...

ナビゲーションプロパティ付き

from supp in db.Supliers
from serv in supp.Services
select ...

またはこのようなもの:

from supp in db.Supliers
select new { supp.Name, ServicesCount = supp.Services.Count() }

EFは、SQLで結合を行う方法を理解します。

ナビゲーションプロパティがあるからといって、常に読み込まれるわけではありません。遅延読み込みを行うには、2つの条件が満たされている必要があります

  1. virtualプロパティは、EFが遅延読み込みを実行するための配線を使用してプロキシタイプでオーバーライドできるように定義する必要があります。
  2. コンテキストで遅延読み込みを有効にする必要があります。これらはデフォルトですが、を設定することでインスタンスごとにオフにすることができますcontext.Configuration.LazyLoadingEnabled = false

したがって、これは遅延読み込みを制御する2つの方法も示しています。構造的または一時的に有効/無効にできます。

それとは別に、2つの方法で反対の熱心な読み込みを制御できます。

  1. Includeステートメントの使用:

    db.Suppliers.Include(s => s.Services)
    
  2. 投影にナビゲーションプロパティを含める:

    from supp in db.Supliers
    from serv in supp.Services
    select new { supp.Name, serv.ServiceName }
    

(もっと多くの方法がありますが、これらは最も重要な方法です)

これは、サービスまたはリポジトリでのlinqクエリの記述に適用されます。IQueryable他の人が言っているように:あなたのサービス/リポジトリメソッドの消費者に公開しないでください。

最後の重要な注意事項:遅延読み込みは、ライフコンテキストの範囲内でのみ可能です。コンテキストが破棄され、遅延読み込みナビゲーションプロパティがアドレス指定されると、例外がスローされます。同時に、寿命の短いコンテキストインスタンスを使用することをお勧めします。したがって、ジレンマがあります。エンティティオブジェクトのみを公開するか、DTOのみを公開するか、モデルなどを表示します。遅延読み込みが有効なエンティティオブジェクトを公開すると、コンシューマーが、まだ読み込まれていないナビゲーションプロパティを誤ってアドレス指定し、コンテキストが失われる可能性があります。

于 2013-02-13T16:04:16.900 に答える
1

一般的に、EF にリポジトリを配置することは常に良い考えだと思います。クライアント側のロジック (またはビジネス ロジック) からデータベース ロジックを抽象化できます。そして、あなたが言及している特定のケースでは、もう1つの優れた利点を実現できます。具体的に呼び出した場合にのみ、必要な情報を取得できます(GetSupplierByCustomerIDあなたが言及した例のように.

あなたが検討するかもしれない別のアプローチは、この質問への回答で私が言及したものです: 境界付けられたコンテキスト. アプリケーションの懸念事項をより分離すればするほど、長い目で見れば、あなたと仲間のプログラマーにとってより良い結果が得られます (特に、すべてを単体テストしたい場合)。

于 2013-02-13T15:08:30.490 に答える