Idov
Idov

Reputation: 5124

Entity Framework DbContext and thread safety

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.

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.

Also I read that in order to make it thread-safe, each action should have its own 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?

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

Upvotes: 11

Views: 12996

Answers (2)

CodeCaster
CodeCaster

Reputation: 151594

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).

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.

Upvotes: 3

Akash Kava
Akash Kava

Reputation: 39916

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.

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

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.

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

Upvotes: 2

Related Questions