web-dev-qa-db-ja.com

エンティティフレームワークのスレッドセーフ

Entity Frameworkによって生成されたコンテキストオブジェクトはスレッドセーフではありません。

スレッドごとに1つ(および各スレッドでSaveChanges()を呼び出す)の2つの別個のエンティティコンテキストを使用するとどうなりますか?これはスレッドセーフですか?

// this method is called from several threads concurrently
public void IncrementProperty()
{
   var context = new MyEntities();

   context.SomeObject.SomeIntProperty++;
   context.SaveChanges();
}

エンティティフレームワークコンテキストは、コンテキスト内の現在の値が新しいかどうかを追跡する何らかの「カウンター」変数を実装していると思います。

  1. 上記のコード(別のスレッドから呼び出されます)を使用しても、増分/保存変更をロックする必要がありますか?
  2. もしそうなら、この単純なシナリオでこれを達成するための好ましい方法は何ですか?
37
Harper

単一のEntity Frameworkコンテキストで動作する複数のスレッドは、スレッドセーフではありません。

各スレッドのコンテキストの個別のインスタンスは、スレッドセーフです。実行の各スレッドにEFコンテキストの独自のインスタンスがある限り、問題ありません。

あなたの例では、そのコードを任意の数のスレッドから同時に呼び出すことができ、それぞれが独自のコンテキストで問題なく動作します。

ただし、次のように、このための「using」ブロックを実装することをお勧めします。

// this method is called from several threads concurrently
public void IncrementProperty()
{
   using (var context = new MyEntities())
   {
      context.SomeObject.SomeIntProperty++;
      context.SaveChanges();
   }
}
42
Jim Reineri

「SomeObject.SomeIntProperty」は静的だと思います。これは、エンティティがスレッドセーフであることとは関係ありません。マルチスレッド環境で静的変数に書き込む場合は、スレッドの安全性を確保するために、それらを常にダブルチェックロックでラップする必要があります。

0
XtremeBytes

ファクトリアプローチを使用して、インスタンス自体ではなくファクトリとしてDbContextを注入できます。これを見てください: https://github.com/vany0114/EF.DbContextFactory

それはより安全であり、インスタンスの作成をリポジトリにハードコードすることを避けます。

http://elvanydev.com/EF-DbContextFactory/

これを非常に簡単な方法で実行するNinjectの拡張機能があります。メソッドkernel.AddDbContextFactory<YourContext>();を呼び出すだけで、Func<YourContext>を受け取ってリポジトリを変更する必要もあります。