Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework lazy loading doesn't work from other thread

I just found out that lazy loading in Entity Framework only works from the thread that created the ObjectContext. To illustrate the problem, I did a simple test, with a simple model containing just 2 entities : Person and Address. Here's the code :

    private static void TestSingleThread()
    {
        using (var context = new TestDBContext())
        {
            foreach (var p in context.Person)
            {
                Console.WriteLine("{0} lives in {1}.", p.Name, p.Address.City);
            }
        }
    }

    private static void TestMultiThread()
    {
        using (var context = new TestDBContext())
        {
            foreach (var p in context.Person)
            {
                Person p2 = p; // to avoid capturing the loop variable
                ThreadPool.QueueUserWorkItem(
                    arg =>
                    {
                        Console.WriteLine("{0} lives in {1}.", p2.Name, p2.Address.City);
                    });
            }
        }
    }

The TestSingleThread method works fine, the Address property is lazily loaded. But in TestMultiThread, I get a NullReferenceException on p2.Address.City, because p2.Address is null.

It that a bug ? Is this the way it's supposed to work ? If so, is there any documentation mentioning it ? I couldn't find anything on the subject on MSDN or Google...

And more importantly, is there a workaround ? (other than explicitly calling LoadProperty from the worker thread...)

Any help would be very appreciated

PS: I'm using VS2010, so it's EF 4.0. I don't know if it was the same in the previous version of EF...

like image 983
Thomas Levesque Avatar asked Apr 04 '10 21:04

Thomas Levesque


1 Answers

Is this by design? Yes; any call to Load, implicit or explicit, will eventually go through the ObjectContext, and ObjectContext is documented to be not thread-safe.

A possible workaround would be to detach the entity from the object context in the worker thread and attach it to an object context in the current thread.

like image 173
Craig Stuntz Avatar answered Oct 23 '22 19:10

Craig Stuntz