メソッド呼び出しによるネストされた DbContext - Entity Framework 質問する

メソッド呼び出しによるネストされた DbContext - Entity Framework 質問する

メソッド呼び出しにより 2 つの DbContext がネストされる次のケース:

public void Method_A() {
    using (var db = new SomeDbContext()) {
        //...do some work here
        Method_B();
        //...do some more work here
    }
}

public void Method_B() {
    using (var db = new SomeDbContext()) {
        //...do some work
    }
}

質問:

  1. このネストによって何か問題が発生しますか? (また、正しい DbContext が正しいタイミングで破棄されますか?)

  2. このネストは悪い習慣だと考えられる場合、Method_A を次のようにリファクタリングする必要がありますか。

    public void Method_A() {
        using (var db = new SomeDbContext()) {
            //...do some work here
        }
    
        Method_B();
    
        using (var db = new SomeDbContext()) {
            //...do some more work here
        }
    }
    

ありがとう。

ベストアンサー1

派生クラスDbContextは実際には少なくとも次の 3 つのことを管理します。

  • データベースとエンティティモデルを記述するメタデータ
  • 基礎となるデータベース接続、および
  • 変更の追跡、関係の修正などのために、コンテキストを使用してロードされたエンティティのクライアント側「キャッシュ」。(適切な言葉がないためこれを「キャッシュ」と呼んでいますが、これは通常短命であり、EF の機能をサポートするためだけのものであることに注意してください。該当する場合、アプリケーションでの適切なキャッシュの代替にはなりません。)

Entity Framework は通常、メタデータ (項目 1) をキャッシュして、すべてのコンテキスト インスタンス (または少なくとも同じ接続文字列を使用するすべてのインスタンス) で共有します。したがって、ここでは心配する必要はありません。

他のコメントで述べられているように、あなたのコードでは 2 つのデータベース接続が使用されることになります。これは問題になる場合とならない場合があります。

また、クライアントキャッシュが2つになります(項目3)。外側のコンテキストからエンティティをロードし、次に内側のコンテキストから再度ロードすると、メモリ内に2つのコピーが存在することになります。これは間違いなく混乱を招き、微妙なバグにつながる可能性があります。つまり、共有コンテキストオブジェクトを使用しない場合は、オプション 2 はオプション 1 よりもおそらく良いでしょう。

使用している場合取引、さらに考慮すべき点があります。複数のデータベース接続があると、トランザクションが分散トランザクションに昇格される可能性が高くなりますが、これはおそらく望ましくありません。db トランザクションについては何も言及されていないため、ここではこれ以上詳しく説明しません。

それで、あなたはどうなるのでしょうか?

DbContextコード内でオブジェクトを受け渡しすることを避けるためだけにこのパターンを使用する場合は、MethodBコンテキストをパラメータとして受け取るようにリファクタリングした方が良いでしょうコンテキストオブジェクトの寿命をどのくらいにするかという問題は、何度も繰り返されます。経験則として、単一のデータベース操作または一連の操作ごとに新しいコンテキストを作成します。関連しているデータベース操作。(例えば、このブログ投稿そしてこの質問

(代わりに、DbContext既存の接続を受け取る派生クラスにコンストラクターを追加することもできます。そうすれば、複数のコンテキスト間で同じ接続を共有できます。)

便利なパターンの 1 つは、コンテキスト オブジェクトを作成し、それをプライベート フィールドまたはプロパティとして保存する独自のクラスを作成することです。次に、クラスを実装しIDisposable、そのDispose()メソッドでコンテキスト オブジェクトを破棄します。呼び出しコードはクラスのインスタンスを作成し、コンテキストや接続についてまったく心配する必要がなくなります。

いつになったら必要複数のコンテキストを同時にアクティブにするには?

これは、マルチスレッドのコードを書く必要があるときに便利です。データベース接続はスレッドセーフではないため、接続(つまりEFコンテキスト)には一度に1つのスレッドからのみアクセスする必要があります。それが厳しすぎる場合は、スレッドごとに1つずつ、複数の接続(およびコンテキスト)が必要です。これ面白い。

おすすめ記事