实体框架DbContext和线程安全

时间:2022-09-15 15:41:09

I need to update a few tables in my DB in a single transaction and I read that using DbContext.SaveChanges should be the way to do so.

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

However I also read that the lifetime of the DbContext should be as short as possible because it grows over time as it loads more entities.

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

Also I read that in order to make it thread-safe, each action should have its own DbContext.

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

Should I have a DbContext for each table I want to change and call SaveChanges on each DbContext? Wouldn't the last SaveChanges call override the changes of the previous calls?

我是否应该为每个要更改的表都有一个DbContext并在每个DbContext上调用SaveChanges?最后的SaveChanges调用不会覆盖先前调用的更改吗?

What is the best way to do it? (I need this for a website)

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

2 个解决方案

#1


2  

Simple way is, to have one DbContext per request, ASP.NET MVC does all thread safety, each controller instance in ASP.NET MVC is isolated for every request, you don't have to worry about race conditions. As long as you don't create threads and just simply do data transformation in action method using single DbContext, you will not have any problem.

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

Basically DbContext does nothing, it just queues SQL query to target database, it is the database which handles multi threading, race conditions. To protect your data, you should use transactions and add validations in your database to make sure they are saved correctly

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

}

If you inherit any class from DbContextController and use DB throughout the life of controller, you will not have any problem.

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

However, if you use any threads like in following example,

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

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

#2


1  

Entity Framework is not thread-safe. An MVC controller is instantiated per request. Thus if you use one DbContext per request, you're safe as long as you don't manually spawn threads in your controller actions (which you shouldn't do anyway).

实体框架不是线程安全的。每个请求实例化一个MVC控制器。因此,如果您为每个请求使用一个DbContext,只要您不在控制器操作中手动生成线程(您不应该这样做),就是安全的。

Now if you have concurrency in your application, like a reservation system where multiple users are out to access the same scarce resources that can run out (like tickets), you'll have to implement logic around that yourself. No thread safety is going to help you there anyway.

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

That's why you're being asked for code in comments, because explaining thread safety in general is way too broad, and probably not applicable to your situation.

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

#1


2  

Simple way is, to have one DbContext per request, ASP.NET MVC does all thread safety, each controller instance in ASP.NET MVC is isolated for every request, you don't have to worry about race conditions. As long as you don't create threads and just simply do data transformation in action method using single DbContext, you will not have any problem.

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

Basically DbContext does nothing, it just queues SQL query to target database, it is the database which handles multi threading, race conditions. To protect your data, you should use transactions and add validations in your database to make sure they are saved correctly

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

}

If you inherit any class from DbContextController and use DB throughout the life of controller, you will not have any problem.

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

However, if you use any threads like in following example,

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

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

#2


1  

Entity Framework is not thread-safe. An MVC controller is instantiated per request. Thus if you use one DbContext per request, you're safe as long as you don't manually spawn threads in your controller actions (which you shouldn't do anyway).

实体框架不是线程安全的。每个请求实例化一个MVC控制器。因此,如果您为每个请求使用一个DbContext,只要您不在控制器操作中手动生成线程(您不应该这样做),就是安全的。

Now if you have concurrency in your application, like a reservation system where multiple users are out to access the same scarce resources that can run out (like tickets), you'll have to implement logic around that yourself. No thread safety is going to help you there anyway.

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

That's why you're being asked for code in comments, because explaining thread safety in general is way too broad, and probably not applicable to your situation.

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