【问题标题】:EF concurency tracking when saving changes from a different thread保存来自不同线程的更改时的 EF 并发跟踪
【发布时间】:2012-01-31 22:55:43
【问题描述】:

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

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

同时,似乎如果Incidents 之一在“网络请求线程”中被myDbContext 更改,即使这些更改暂时保存到数据库中,它们也会被一组Incidents,在用户使用网页更改 Incident 之前几分钟被后台线程拉取。

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

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

来自后台线程的代码:

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();
            }

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

【问题讨论】:

    标签: .net entity-framework concurrency dbcontext


    【解决方案1】:

    只需调用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();
    

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

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

    【讨论】:

    • 是的。自从我发现以来,我已经向问题主体写了一个更新,我误导了问题读者关于问题设置的信息。请看一看。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-06
      • 2016-12-18
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      相关资源
      最近更新 更多