Good advices to use EF in a multithread program? Good advices to use EF in a multithread program? multithreading multithreading

Good advices to use EF in a multithread program?


Good advice is - just don't :-) EF barely manages to survive one thread - the nature of the beast.

If you absolutely have to use it, make the lightest DTO-s, close OC as soon as you have the data, repack data, spawn your threads just to do calculations and nothing else, wait till they are done, then create another OC and dump data back into DB, reconcile it etc.

If another "main" thread (the one that spawns N calculation threads via TPL) needs to know when some ther thread is done fire event, just set a flag in the other thread and then let it's code check the flag in it's loop and react by creating new OC and then reconciling data if it has to.

If your situation is more simple you can adapt this - the key is that you can only set a flag and let another thread react when it's ready. That means that it's in a stable state, has finished a round of whatever it was doing and can do things without risking race conditions. Reset the flag (an int) with interchaged operations and keep some timing data to make sure that your threads don't react again within some time T - otherwire they can spend their lifetime just querying DB.


This is how I implemented it my scenario.

var processing= new ConcurrentQueue<int>();//possible multi threaded enumeration only processed non-queued recordsParallel.ForEach(dataEnumeration, dataItem=>{     if(!processing.Contains(dataItem.Id))     {         processing.Enqueue(dataItem.Id);          var myEntityResource = new EntityResource();          myEntityResource.EntityRecords.Add(new EntityRecord                                      {                                        Field1="Value1",                                         Field2="Value2"                                      }                               );           SaveContext(myEntityResource);       var itemIdProcessed = 0;       processing.TryDequeue(out itemIdProcessed );     }}public void RefreshContext(DbContext context)    {        var modifiedEntries = context.ChangeTracker.Entries()            .Where(e => e.State == EntityState.Modified || e.State == EntityState.Deleted);        foreach (var modifiedEntry in modifiedEntries)        {            modifiedEntry.Reload();        }    }public bool SaveContext(DbContext context,out Exception error, bool reloadContextFirst = true)    {        error = null;        var saved = false;        try        {            if (reloadContextFirst)                this.RefreshContext(context);            context.SaveChanges();            saved = true;        }        catch (OptimisticConcurrencyException)        {            //retry saving on concurrency error            if (reloadContextFirst)                this.RefreshContext(context);            context.SaveChanges();            saved = true;        }        catch (DbEntityValidationException dbValEx)        {            var outputLines = new StringBuilder();            foreach (var eve in dbValEx.EntityValidationErrors)            {                outputLines.AppendFormat("{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:",                    DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State);                foreach (var ve in eve.ValidationErrors)                {                    outputLines.AppendFormat("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage);                }            }            throw new DbEntityValidationException(string.Format("Validation errors\r\n{0}", outputLines.ToString()), dbValEx);        }        catch (Exception ex)        {            error = new Exception("Error saving changes to the database.", ex);        }        return saved;    }


I think Craig might be right about your application no needing to have threads.. but you might look for the uses of ConcurrencyCheck in your models to make sure you don't "override" your changes