实体框架DbContext和线程安全

时间:2015-09-05 08:43:46

标签: c# asp.net-mvc multithreading entity-framework

我需要在单个事务中更新数据库中的几个表,并且我认为使用DbContext.SaveChanges应该是这样做的。

但是我也读到DbContext的生命周期应该尽可能短,因为它会随着时间的推移而增加,因为它会加载更多的实体。

此外,我读到为了使其成为线程安全的,每个操作都应该有自己的DbContext

我是否应该为每个要更改的表格DbContext,并在每个SaveChanges上致电DbContext?最后SaveChanges次呼叫是否会覆盖之前呼叫的更改?

最好的方法是什么? (我需要这个网站)

2 个答案:

答案 0 :(得分:2)

简单的方法是,每个请求都有一个DbContext,ASP.NET MVC可以完成所有线程安全,ASP.NET MVC中的每个控制器实例都是针对每个请求进行隔离的,您不必担心竞争条件。只要您不使用单个DbContext创建线程并且只是在动作方法中进行数据转换,就不会有任何问题。

基本上DbContext什么都不做,它只是将SQL查询排队到目标数据库,它是处理多线程,竞争条件的数据库。为了保护您的数据,您应该使用事务并在数据库中添加验证以确保它们得到正确保存

public abstract class DbContextController : Controller{

    public AppDbContext  DB { get; private set;}

    public DbContextController(){
        DB = new AppDbContext();
    }

    protected override void OnDisposing(bool disposing){
        DB.Dispose();
    }

}

如果从DbContextController继承任何类并在控制器的整个生命周期中使用DB,则不会有任何问题。

public ActionResult ProcessProducts(){
    foreach(var p in DB.Products){
       p.Processed = true;
       foreach(var order in p.Orders){
          order.Processed = true;
       }
    }
    DB.SaveChanges();
}

但是,如果您使用以下示例中的任何线程,

public ActionResult ProcessProducts(){
    Parallel.ForEach(DB.Products, p=>{
         p.Processed = true;
         // this fails, as p.Orders query is fired
         // from same DbContext in multiple threads
         foreach(var order in p.Orders){
             order.Processed = true;
         }
    });
    DB.SaveChanges(); 
}

答案 1 :(得分:1)

Entity Framework is not thread-safeAn MVC controller is instantiated per request。因此,如果您为每个请求使用一个DbContext,只要您不在控制器操作中手动生成线程(您无论如何都不应该这样做),您就是安全的。

现在,如果您的应用程序中有并发,就像预订系统中有多个用户可以访问可用的相同稀缺资源(如门票),您必须自己实现逻辑。无论如何,没有线程安全可以帮助你。

这就是为什么在评论中要求您提供代码的原因,因为解释一般的线程安全性过于宽泛,可能不适用于您的情况。