我需要在单个事务中更新数据库中的几个表,并且我认为使用DbContext.SaveChanges
应该是这样做的。
但是我也读到DbContext
的生命周期应该尽可能短,因为它会随着时间的推移而增加,因为它会加载更多的实体。
此外,我读到为了使其成为线程安全的,每个操作都应该有自己的DbContext
。
我是否应该为每个要更改的表格DbContext
,并在每个SaveChanges
上致电DbContext
?最后SaveChanges
次呼叫是否会覆盖之前呼叫的更改?
最好的方法是什么? (我需要这个网站)
答案 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-safe。 An MVC controller is instantiated per request。因此,如果您为每个请求使用一个DbContext,只要您不在控制器操作中手动生成线程(您无论如何都不应该这样做),您就是安全的。
现在,如果您的应用程序中有并发,就像预订系统中有多个用户可以访问可用的相同稀缺资源(如门票),您必须自己实现逻辑。无论如何,没有线程安全可以帮助你。
这就是为什么在评论中要求您提供代码的原因,因为解释一般的线程安全性过于宽泛,可能不适用于您的情况。