Using a single context from many threads in Entity Framework 6

c# entity-framework multithreading thread-safety

Question

Is there a way to use one dbContext in a different threads asynchronously?

 var context = new Entities();
 Task.Factory.StartNew(() => context.Companies.Include(x => x.Address).First());
 Task.Factory.StartNew(() => context.Companies.Include(x => x.Owner).First());
 //after some changes...
 context.SaveChanges();
 context.Dispose();

The main idea is to save everything at once and if something fail to return all changes. In the reality I'm using Unit of Work object which is passed to viewmodel and its child viewmodels so they try to get information asynchronously... The code above illustrates the problem. The code above will throw an exception:

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.

The main problem is if I'd like to use multiple instances of DbContext each of the Data Transfer Object will contains different information for the fields. Any suggestions? Thanks!

1
2
12/18/2013 7:52:54 PM

Accepted Answer

A context is not thread-safe. Period. So never ever address a context from multiple threads and don't jump through hoops to try and make it thread-safe.

You can simply wrap your code in a TransactionScope and start each Task with an action that creates its own context and saves its changes:

using (var tran = new TransactionScope())
{
    Task.Factory.StartNew(() => DoSomething());
    Task.Factory.StartNew(() => DoSomethingElse());
    // Wait all
    tran.Complete();
}
7
12/19/2013 7:59:13 AM

Popular Answer

If you are using SimpleInjector to get an instance of your DbContext then you will have a problem of thread-safe.

For this scenario, you need to use ThreadScopedLifestyle and encapsulate your code. See:

Container container = new Container();
container.Options.DefaultScopedLifestyle = new     SimpleInjector.Lifestyles.ThreadScopedLifestyle();
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);

using (SimpleInjector.Lifestyles.ThreadScopedLifestyle.BeginScope(container))
{
    var _uow = container.GetInstance<IUnitOfWork>();
    // put your business code here ...
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow