4

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.

Community
  • 1
  • 1
Leslie
  • 41
  • 2
  • What's the database behind it? Is it Oracle? – Michal B. May 09 '12 at 14:57
  • 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 May 09 '12 at 15:01
  • This is a SQLServer database. – Leslie May 09 '12 at 15:14
  • @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 May 09 '12 at 15:23
  • @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 May 09 '12 at 15:31
  • @Slugart I already tried cleaning and rebuilding, and it still throws the exception in a random way. Changing my code by: Entities ent = new Entities(); if (ThreadContexts != null && threadId!= null && ent != null) ThreadContexts.Add(threadId, ent); It enters the if statement and then still throws the exception. – Leslie May 09 '12 at 15:58
  • You should use a [thread-safe dictionary](http://msdn.microsoft.com/en-us/library/dd287191.aspx). – Gert Arnold May 09 '12 at 18:23
  • The ConcurrentDictionary seems to work great. Thank you GertArnold! And thanks to all for you help. Is there a way to put the post as resolved? – Leslie May 10 '12 at 07:58
  • I put it into an answer, with another suggestion. – Gert Arnold May 10 '12 at 20:45

1 Answers1

1

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>));
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291