保存来自不同线程的更改时的EF并发跟踪

时间:2012-01-31 22:55:44

标签: .net entity-framework concurrency dbcontext

我有一个EF代码优先生成的数据库。使用DbContext完成数据操作。 Asp.net应用程序中的IoC容器生成DbContext实例,BL对象依赖于每个线程。这是一个后台任务类,它与Web应用程序一起加载。

每隔一段时间(每10分钟一次),后台线程通过在事务范围内调用Incidents将一个项添加到myDbContext.Add列表中。

与此同时,似乎Incidents中的一个myDbContext在“Web请求线程”中被Incidents更改,即使更改被保存到数据库片刻,它们也会被覆盖在用户使用网页改变Incident之前的几分钟,由using (var transaction = new TransactionScope()) { foreach (var scheduledTask in _db.ScheduledTasks) { if (scheduledTask.NextExecuteAfterDate == null) { PopulateNextExecuteAfterDate(scheduledTask); shouldSaveChanges = true; } if (DateTime.Now > scheduledTask.NextExecuteAfterDate) { RegisterRecurringTicket(scheduledTask); CalculateNextTime(scheduledTask); shouldSaveChanges = true; } } if (shouldSaveChanges) _db.SaveChanges(); transaction.Complete(); } 的集合提取。

这似乎是一个并发问题(我没有像Timestamp列那样实现任何可靠性。)

我的问题是:后台线程不应该只保存更改的数据(在我的情况下,添加新事件),留下整个事件集合吗?如果确实如此,我的问题来源就是其他地方。

后台线程中的代码:

RegisterRecurringTicket(scheduledTask);

子例程_db.SaveChanges();中的代码将项添加到事件集合中。当调用{{1}}时,似乎事件集合被旧的事件集覆盖,将UI生成的更改转换为过时的事件集合。如果是这样,我该如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

简单地调用myDbContext.Incidents.ToList()不会导致在数据库中覆盖任何内容。 然而,我很容易想象出这样的情况:

// My Incident tracker
IEnumerable<Incident> CurrentIncidents {get{return myDbContext.Incidents.ToList();}}

// Meanwhile, in another class on the same thread...
foreach(var incident in IncidentTracker.CurrentIncidents)
{
   var claims = myDbContext.Claims.Where(c => c.IncidentId == incident.IncidentId);
   foreach(var claim in claims)
   {
      Process(claim);
   }
   incident.Processed = true;
}
myDbContext.SaveChanges();

在上面的示例中,即使您没有直接从Incident提取myDbContext,因为两个类都注入了相同的上下文,因此调用SaveChanges()实际上会影响{{1}}声明(您想要更改)和事件(您没有更改)。

这样的事情有可能发生吗?

答案 1 :(得分:0)

问题在于我正在使用PerThreadScope DbContext注射。这导致我的ASP.NET应用程序出现意外行为。设置Ninject模块以解决DbContext中的PerRequestScope问题。