实体框架6无法完成多项任务

时间:2019-03-12 13:43:23

标签: c# multithreading entity-framework

我有一个标准的客户端-服务器系统,可以使用从服务器获取实体,在客户端中对其进行更新并发送回服务器以进行保存(断开连接的实体保存)。 效果很好。 但是,当我尝试使用TPL(Task.Run ...)运行相同的代码时,出现以下异常:

  

System.InvalidOperationException:实体对象不能为   由IEntityChangeTracker的多个实例引用。在   System.Data.Entity.Core.Objects.ObjectContext.VerifyContextForAddOrAttach(IEntityWrapper   wrapEntity)在   System.Data.Entity.Core.Objects.ObjectContext.AttachSingleObject(IEntityWrapper   wrapEntity,EntitySetentitySet)   System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.AddEntityToObjectStateManager(IEntityWrapper   wrapEntity,布尔值doAttach)在   System.Data.Entity.Core.Objects.DataClasses.EntityReference.AddEntityToObjectStateManager(IEntityWrapper   wrapEntity,布尔值doAttach)位于...

这是我在服务器中尝试运行在其他任务中的代码:

using (var dal = UnityManager.Instance.Resolve<IRepositoryDbContextDal>())
{
    dal.Set(entity.GetType()).Attach(entity);
    dal.Entry(entity).State = EntityState.Modified;
    dal.SaveChanges();
}

UnityManager给我一个包装DbContext的新类

1 个答案:

答案 0 :(得分:0)

您面临的问题是您正在跨多个活动DbContext关联实体。通常,这意味着您有一个DbContext,您认为它已经死了并且已经被处置,但是还没有。

作为一个简单的例子:

Course testCourse = null;
using (var context = new EntityContext())
{
   testCourse = context.Courses.Single(x => x.CourseId == 3);
}
testCourse.Name = "UpdatedTest2";
using (var context = new EntityContext())
{
    context.Courses.Attach(testCourse);
    context.Entry(testCourse).State = EntityState.Modified;
    context.SaveChanges();
}

上面的代码有效。我们使用一个上下文加载一个实体,该上下文被放置(使用块结束),因此该实体现在未被跟踪。我们可以对其进行修改,将其附加到另一个DbContext,将其状态设置为“已修改”,然后保存。

现在使用以下代码:

Course testCourse = null;
var openContext = new EntityContext();
testCourse = openContext.Courses.Single(x => x.CourseId == 3);
testCourse.Name = "UpdatedTest2";

using (var context = new EntityContext())
{
    context.Courses.Attach(testCourse);
    context.Entry(testCourse).State = EntityState.Modified;
    context.SaveChanges();
}

此代码非常相似,但请注意,原始上下文并未处理。我们加载该实体并对其进行修改,但随后尝试将其与另一个上下文关联以进行保存。我们得到了多实体变更跟踪器异常。

您知道不会处理上下文的简单解决方法,并且您确实确实需要将实体与第二个上下文相关联,是将实体与原始上下文明确分离:

Course testCourse = null;
var openContext = new EntityContext();
testCourse = openContext.Courses.Single(x => x.CourseId == 3);
openContext.Entry(testCourse).State = EntityState.Detached; // Remove association from original context.
testCourse.Name = "UpdatedTest2";

using (var context = new EntityContext())
{
    context.Courses.Attach(testCourse);
    context.Entry(testCourse).State = EntityState.Modified;
    context.SaveChanges();
}

但是,在大多数情况下,这只是隐藏了您无法解决的DbContext潜在问题。此处的关键是确保处置创建的所有DbContext。 (using阻止了new建立的任何DbContext)如果您使用的是IoC容器,则需要了解它们如何将生存期作用域分配给它们注入的依赖项。