Entity Framework Thread Safety
Asked Answered
P

3

46

The context objects generated by Entity Framework are not thread-safe.

What if I use two separate entity contexts, one for each thread (and call SaveChanges() on each) - will this be thread-safe?

// this method is called from several threads concurrently
public void IncrementProperty()
{
   var context = new MyEntities();

   context.SomeObject.SomeIntProperty++;
   context.SaveChanges();
}

I believe entity framework context implements some sort of 'counter' variable which keeps track of whether the current values in the context are fresh or not.

  1. With the code above - called from separate threads - do I still need to lock around the increment/savechanges?
  2. If so, what is the preferred way to accomplish this in this simple scenario?
Palp answered 15/12, 2010 at 22:31 Comment(3)
"The context objects generated by Entity Framework are not thread-safe." - why do you say that?Motivation
I am referring to MSDN: msdn.microsoft.com/en-us/library/… where it says "The ObjectContext class is not thread safe."Palp
Yep, that's what i thought you meant - the context, not the entities. Which is why you should never use a singleton for the OC.Motivation
V
48

More than one thread operating on a single Entity Framework context is not thread safe.

A separate instance of context for each thread is thread-safe. As long as each thread of execution has its own instance of EF context you will be fine.

In your example, you may call that code from any number of threads concurrently and each will be happily working with its own context.

However, I would suggest implementing a 'using' block for this as follows:

// this method is called from several threads concurrently
public void IncrementProperty()
{
   using (var context = new MyEntities())
   {
      context.SomeObject.SomeIntProperty++;
      context.SaveChanges();
   }
}
Verlinevermeer answered 15/12, 2010 at 22:58 Comment(3)
Thanks. So does the actual value of SomeIntProperty get read when you do SubmitChanges() or at what time? I mean if the first thread increments the value to 3, will the second thread potentially still have value 2 cached somewhere, or will it retrieve the value on the spot?Palp
I overlooked a couple of important aspects of your example. First, you have no code that retrieves and instance 'SomeObject'. So as shown the code will not work. There is no sharing of caches, buffers or locks between contexts. So, each thread with its context instance can be thought of in the same manner that you would think the process running on two different machines. So you have to deal with database concurrency issues accordingly.Verlinevermeer
You would need to implement optimistic concurrency or a database transaction to deal with the database concurrencly issues.Verlinevermeer
S
1

You can use the factory approach inject your DbContext as a factory instead of an instance perse, take a look at this: https://github.com/vany0114/EF.DbContextFactory

It's safer and you avoid to hardcode the instance creation into your repositories.

http://elvanydev.com/EF-DbContextFactory/

There is an extension to Ninject to do that in a very easy way, just calling the method kernel.AddDbContextFactory<YourContext>(); also you need to change your repository by receiving a Func<YourContext>

Sooksoon answered 29/11, 2017 at 5:26 Comment(0)
V
0

I believe "SomeObject.SomeIntProperty" is static. This has nothing to do with Entity being threadsafe. If you are writing to a Static variables in a multithreaded environment you should always wrap them with a double check lock to ensure thread safety.

Valdes answered 15/12, 2010 at 22:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.