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();
}
エンティティフレームワークコンテキストは、コンテキスト内の現在の値が新しいかどうかを追跡する何らかの「カウンター」変数を実装していると思います。
単一の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();
}
}
「SomeObject.SomeIntProperty」は静的だと思います。これは、エンティティがスレッドセーフであることとは関係ありません。マルチスレッド環境で静的変数に書き込む場合は、スレッドの安全性を確保するために、それらを常にダブルチェックロックでラップする必要があります。
ファクトリアプローチを使用して、インスタンス自体ではなくファクトリとしてDbContextを注入できます。これを見てください: https://github.com/vany0114/EF.DbContextFactory
それはより安全であり、インスタンスの作成をリポジトリにハードコードすることを避けます。
http://elvanydev.com/EF-DbContextFactory/
これを非常に簡単な方法で実行するNinjectの拡張機能があります。メソッドkernel.AddDbContextFactory<YourContext>();
を呼び出すだけで、Func<YourContext>
を受け取ってリポジトリを変更する必要もあります。