Entity Framework DbContext和线程安全性

9
我需要在单个事务中更新几个表格,我读到使用DbContext.SaveChanges应该是这样做的方法。
然而,我也读到DbContext的生命周期应该尽可能短,因为随着加载更多实体,它会随着时间增长。
此外,我读到为了使其线程安全,每个操作都应该有自己的DbContext
我应该为要更改的每个表格都有一个DbContext,并在每个DbContext上调用SaveChanges吗?最后一个SaveChanges调用不会覆盖前面的调用所做的更改吗?
什么是最好的方法?(我需要这个网站)

如果您想在单个事务中完成所有操作,那么单个DbContext就足够了。不必担心线程安全性,因为您需要按顺序执行所有操作。 - DavidG
1
@DavidG:但是如果两个用户同时尝试使用相同的DbContext,那么不会导致竞争条件吗? - Idov
DavidG是正确的,可以将所有记录插入到任意数量的表中。保存后处理数据库上下文。但是,让数据库上下文挂起并重复使用相同的上下文进行多个Web请求并不是一个好主意。 - Steven Yates
2
你真的应该展示一些代码。我有一种感觉,当你谈论共享上下文和需要互斥量时,你可能正在做一些非常糟糕的事情,但如果我们不看到具体发生了什么,我们就无法给出任何具体的建议。 - Gert Arnold
@GertArnold:我不想使用互斥锁 :),而且我还没有代码展示。我只是想知道哪种方法是最好的。 - Idov
显示剩余3条评论
2个回答

3
Entity Framework 不是线程安全的。每个请求都会实例化一个 MVC 控制器,因此,如果您在每个请求中使用一个 DbContext,只要您不在控制器操作中手动创建线程(无论如何都不应该这样做),就是安全的。

但是,如果您的应用程序具有 并发性,例如预订系统,在该系统中,多个用户需要访问可能会耗尽的相同稀缺资源(例如票据),那么您将不得不自己实现其周围的逻辑。任何线程安全都无法帮助您。

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


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继承任何类,并在控制器的整个生命周期中使用数据库,那么你将不会遇到任何问题。

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(); 
}

基本上 DbContext 什么也不做... 真棒! - Matthew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接