Entity FrameworkのDataContextオブジェクトを作成して、各CRUDメソッドのusingブロックに配置しても問題ありませんか?


10

次の機能を実装するwpfアプリケーションを構築しています。

  1. ユーザー入力を取得し、データベースからデータを読み取る
  2. それにいくつかの計算を行います
  3. 複数のタイプのビューでユーザーにそれを紹介し、変更をデータベースに書き込みます

提案されたアーキテクチャ:データベース->エンティティフレームワーク->リポジトリ->ビジネスロジック->データサービス-> ViewModel

このアーキテクチャを使用する理由:アプリケーション(複数のビュー)と複数のデータベースに存在する複数のシナリオ。したがって、私は抽象化のために真ん中にリポジトリを使用する用意があります。

注意点の1つは、リポジトリが実装されている場合、コンテキストは長期間有効であることです。これを克服するために、コンテキストを作成し、それらを各クラッドメソッドのusing()ブロックに配置しても問題ありませんか?

別のアプローチを提案すること自由に感じなさい。


クエリに似たこのスレッドを見てください。stackoverflow.com/questions/21875816/...
ゴピナス

回答:


16

データアクセスまたはトランザクションごとに1つのDbContextオブジェクトを使用します。

DbContext軽量オブジェクトです。ビジネストランザクションごとに1回使用するように設計されていますDbContextシングルトンを 作成してアプリケーション全体で再利用すると、同時実行性やメモリリークの問題など、他の問題が発生する可能性があります。

DbContext本質的に作業ユニットを実装します。 それに応じてそれを扱います。

DbContextオブジェクトを破棄しないでください。

はをDbContext実装IDisposableしていますが、手動で廃棄したり、usingステートメントでラップしたりしないでください。 DbContext自身の寿命を管理します。データアクセスリクエストが完了すると、DbContextはデータベース接続を自動的に閉じます。

これが当てはまる理由を理解するには、からエンティティコレクションに対してLinqステートメントを実行するとどうなるかを考えてくださいDbContextIQueryableデータアクセスメソッドから遅延読み込みを返す場合、クライアントが(を呼び出すかFirstOrDefault()ToList()それを反復することによって)データを強制するまで実際には実行されないパイプラインを立ち上げます。

さらに読書
ドゥ私はいつも私のDbContextオブジェクト上のDispose()を呼び出す必要がありますか?
なぜあなたは、Entity Frameworkでシングルトンのdatacontextsを使うべきではない
戻るIEnumerable<T>IQueryable<T>
万一リポジトリ復帰IQueryable


4
誰かがこのような例外的なケースを思いつくことは間違いありませんが、データアクセスクラスからマテリアライズされていないIQueryableを返すための良いユースケースは思いつきません。これは、呼び出しコードに、データアクセス(おそらくビジネスで実行されていない何か)に到達して機能を操作する機能を提供するだけです。とはいえ、usingブロックの使用を心配することは本当にそれほど大きな懸念事項ですか?それとも、あなたが提案したようにIQueryableを使用することは問題に値するだろういくつかのケースを考えていませんか?
2017年

@Becuzz:DbContextは自身の寿命を管理する責任があります。私の提案は、それを可能にすることです。IQueryableまたはを使用していても機能しIEnumerableます。遅延読み込みで考えられる最も明らかな使用例は、関連するコレクションを含むViewModelオブジェクトを返すが、コレクションが使用されない(または部分的にしか使用されない)場合です。 IQueryable未使用のレコードを取得するコストを回避できます。
ロバートハーベイ

3
私はそのすべてを理解しています。人々がIQueryableをあちこちに返すようにさせられて、私はやけどを負っただけです。そして、チェーンのさらに上の何かが、(DBパフォーマンスの観点から)恐ろしく悪いクエリを作成するためのいくつかのインクルードまたはその他のものを追加しました。そして、それは追跡する楽しいバグでした。そのため、IQueryableを返すことが良いアイデアかどうかを考える機会がありました。そして、メンテナンスの手間がかかるような時間は考えられませんでした。(続き)
Becuzz 2017年

4
@RobertHarvey IQueryableをクライアントに返す場合、リポジトリレイヤーの正確なポイントは何ですか?あなたは基本的にクライアントにクエリを書くオプションを与えています-それらがSQLクエリではないがそれでもそれらはクエリ(C#を使って書かれたもの)であり、それは至る所にあることを確認してください。リポジトリがIQueryableを返している場合は、リポジトリを破棄することもできます。
CodingYoshi 2017年

8
@RobertHarvey DbContextを破棄しないことに同意し、参照された記事にも同意しません。全体のアイデアは、インターフェイスに対してコード化することであり、インターフェイスはそれがIDisposableであることを教えてくれます。EFチームがDbContextを実装した方法の内部の仕組みに基づいてコードを記述したり、そのチームの開発者を追跡したりすることはありません。彼らはいつでも変更できます。また、自分や他の開発者に、各クラスの内部の仕組みを調べて、IDisposableが本当に役立つかどうかを確認するよう依頼するつもりはありません。私は、チームの開発者が常にそうではないことを尋ねるだけのために処分するように働きすぎました。
CodingYoshi 2017年

-3

理想的には、コンテキストは、1つのトランザクションに対して初期化および終了する必要があります。あなたの場合、コンテキストはビジネスロジックでインスタンス化され、データの読み取り/書き込みのためにリポジトリに渡される必要があります。


2
はい、ビジネスロジックはデータアクセスと密接に結合されていると、より保守し
やすくなり

-3

アプリケーションの各メソッドでDbContextを呼び出すと、メモリリークが発生します。DbContextの単一のインスタンスを使用します。次の例のコメントを参照してください。

public bool IsInStock(int _ProductId)
{
  var result = false;

  try
  {
    using (var dataService = new StoreDbDataService()) // NB: This line on each method will eventually cause memory leak.
    {
      result = dataService.IsInStock(_ProductId);
    }
  }
  catch (Exception ex)
  {
    Log.LogException(ex);
  }

  return result;
}

1
DbContextを呼び出すとメモリリークが発生する理由を説明できますか?ソースのコメントは私がそれを理解するのに役立ちません。私は、usingブロックによって、StoreDBDataServiceでDisposeが呼び出され、最終的に割り当てられたすべてのリソースがクリーンになると思いますか?
Kasper van den Berg、

これは基本的にRon Swansonの「許可」クリップですが、コード内にあります。
ダグルームズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.