实体框架DbContext和线程安全

Ido*_*dov 7 c# asp.net-mvc multithreading entity-framework

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

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

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

我应该有一个DbContext,因为我想改变,并呼吁每个表SaveChanges上的每一个DbContext?最后一次SaveChanges通话是否会覆盖之前通话的更改?

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

Aka*_*ava 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();
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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

但是,如果您使用任何线程,如下例所示,

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(); 
}
Run Code Online (Sandbox Code Playgroud)