DbContext线程安全吗?

我想知道是否DbContext类是线程安全的,我假设它不是,因为我目前正在执行DbContext线程访问我的应用程序中的DbContext ,我得到了一大堆的lockingexception和其他东西看起来像他们可能是线程有关。

直到最近我没有得到任何错误…但直到最近我没有访问线程中的DbContext

如果我是对的,人们会提出什么样的解决scheme?

这不是线程安全的。 只需在你的线程中创build一个DbContext的新实例。

不,它不是线程安全的 – 整个EF不是线程安全的,因为永远不会共享EF上下文。

下面编辑 – 旧的答案。

我现在总是在DbContext中使用这个模式:

 using(var db = new LogDbContext()) { // Perform work then get rid of the thing } 

我的每个请求线程的方法意味着DbContext中的caching对象将会停滞并变得陈旧,即使其他DbContext实例正在向它后面的实际数据库写入新值。 这会产生一些奇怪的问题,例如一个请求执行一个插入,另一个请求列表进入另一个线程,该线程有一个caching的,陈旧的查询数据列表。

有一些方法可以使下面的工作,甚至提高多读/less写风格的应用程序的性能,但他们采取更多的devise和策略比上述更简单的模式。

更新

我也为库方法使用了一个有用的帮助方法,例如logging调用。 这是辅助方法:

  public static void Using(Db db, Action<Db> action) { if (db == null) { using (db = new Db()) { action(db); } } else { action(db); } } 

有了这个,我可以轻松地编写采用可选的现有DbContext的代码,或者在使用的上下文中实例化一个代码,具体取决于如何调用它。

例如,在使用DbContext的同时,我可能会加载一些数据,logging一些信息,然后保存这些数据 – 最好从性能的angular度来看,使用相同的DbContext。 另一方面,我可能也想logging一些事情,以响应一个简单的行动,既不加载也不写任何其他数据。 通过利用上面的方法,我可以只有一个日志logging方法,无论你是否想在现有的DbContext中工作:

 public void WriteLine(string line, Db _db = null) { Db.Using(_db, db => { db.LogLines.Add(new LogLine(line)); db.SaveChanges(); }); } 

现在这个方法调用可以在现有的DbContext的内部或外部调用,而且仍然是正确的方式,而不是有2个版本的这个和其他所有便利日志logging方法或其他实用工具方法,而不必知道和计划每一个将会对他们或他们的呼叫者进行的呼叫的上下文。 这基本上回到了我下面的线程静态策略的好处之一,我不必担心公用事业调用打开数据库应该担心的时间。

老答案

我通常使用EF DbContext处理线程安全性,如下所示:

 public class LogDbContext : DbContext { . . . [ThreadStatic] protected static LogDbContext current; public static LogDbContext Current() { if (current == null) current = new LogDbContext(); return current; } . . . } 

有了这个地方,我可以得到这样的线程的DbContext:

 var db = LogDbContext.Current(); 

需要注意的是,由于每个DbContext都有自己的本地caching,因此每个线程都会有自己独立的实体对象caching,如果您没有做好准备,会引入一些疯狂的行为。 但是,创build新的DbContext对象可能很昂贵,而且这种方法可以最大限度地降低成本。