2

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!

2 Answers 2

7

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();
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, your idea cross my mind, but when the time for SaveChanges() comes the last SaveChanges throw an exception which says "Statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded."
That means you've become your own concurrent user. You update the same records from different threads.
@Teomanshipahi Use lock, where? Anyway, no, don't even try to use a context in a thread-safe manner.
@GertArnold got you, it is better to go with "Context per thread" solution.
can we create a new thread to do second operation instead use TransactionScope
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.