4
votes

I'm saving data using the Entity Framework in a Parallel.ForEach loop. Knowing that the EF is not thread-safe, I instanciate an entity context for each of my thread.

1- Is it safe? It seems to be as I see in these posts:

Entity Framework + Multiple Threads + Lazy Load

Is it safe to use one Entity Framework Context per thread? ... yes? how?

2-There is an exception during the creation of my context, but only one time out of 3 and I can't found out why.

Here is my code creating the context:

public partial class Entities
{
    private static Entities mfgEntities = new Entities();
    private static readonly Dictionary<int,Entities>  ThreadContexts = new Dictionary<int, Entities>();

    public static Entities Context
    {
        get
        {
            if (HttpContext.Current != null)
            {
                string objectContextKey = HttpContext.Current.GetHashCode().ToString("x");
                if (!HttpContext.Current.Items.Contains(objectContextKey))
                {
                    HttpContext.Current.Items.Add(objectContextKey, new Entities());
                }
                return HttpContext.Current.Items[objectContextKey] as Entities;
            }
            else
            {
                int threadId = Thread.CurrentThread.ManagedThreadId;
                if (!ThreadContexts.ContainsKey(threadId))
                {
                    try
                    {
                        ThreadContexts.Add(threadId, new Entities());
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Erreur lors de la création de l'entity context");
                    }
                }
                return ThreadContexts[threadId];
            }
            return mfgEntities;
        }
    }
}

It throws a NullReferenceException on line :

ThreadContexts.Add(threadId, new Entities());

And ThreadContexts, threadId and the new Entities are not null.

I thank you for your help.

1
What's the database behind it? Is it Oracle? - Michal B.
It's impossible for a NullRef exception to be thrown on that line. Are you compiling with debug symbols? Are you sure that when you break you're on the right thread's call stack? - Slugart
This is a SQLServer database. - Leslie
@Slugart I'm compiling in debug mode and I'm quite sure I break on the right thread's call. I'm also confused with this NullReferenceException on that line but that's what's happening. - Leslie
@Leslie I would try making things more explicit to expose the impossibility of the exception. Break out new Entities() into a var and then assert not null on each of the three vars before calling Add(). Also try cleaning and rebuilding everything. - Slugart

1 Answers

1
votes

You should use a ConcurrentDictionary for ThreadContexts.

Better even: find a way to capture a context instance in a thread, e.g. by executing parallel tasks:

var task1 = new Task(() => <your method that instantiates a context>));