views:

355

answers:

1

Hi,

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

+1  A: 

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.

Craig Stuntz
Thanks for your answer. Unfortunately, in my case creating another object context is definitely overkill. I'm trying to load images into a WPF application using an async binding, and I really don't want to create a new context for each of image (roughly 150 images currently)
Thomas Levesque
I think that at this point you have a WPF question, not an EF question. The EF's rules are very simple. How to follow them using WPF is another issue.
Craig Stuntz
Well, I'm using it in WPF, but it's not a WPF-specific issue. And the only thing about threading in the documentation is the usual "thread safety" information which is the same for almost all classes. It says *are not guaranteed to be thread safe*, not *can't be used by multiple threads*. Not being thread safe doesn't mean that you can't use multi threading at all, it just means you have to handle synchronization yourself.
Thomas Levesque
You are using WPF, therefore you must solve the problem using that tool. Don't mistake the manual: "not guaranteed to be thread safe" means "uses stuff like DB connections from unspecified providers, which, at some point, will almost certainly be unsafe for multithreading." In other words, it's not just about `ObjectContext`. It's about everything it could depend on.
Craig Stuntz