实体框架6在多任务上失败 [英] Entity framework 6 fails on multi tasks

查看:64
本文介绍了实体框架6在多任务上失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a standard client-server system to use getting entities from server, updating them in client and send back to server to save it (disconnected entity save). It works good. But when I try to run the same code using TPL (Task.Run...) I get the following exception:

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)位于...

System.InvalidOperationException: An entity object cannot be referenced by multiple instances of IEntityChangeTracker. at System.Data.Entity.Core.Objects.ObjectContext.VerifyContextForAddOrAttach(IEntityWrapper wrappedEntity) at System.Data.Entity.Core.Objects.ObjectContext.AttachSingleObject(IEntityWrapper wrappedEntity, EntitySet entitySet) at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.AddEntityToObjectStateManager(IEntityWrapper wrappedEntity, Boolean doAttach) at System.Data.Entity.Core.Objects.DataClasses.EntityReference.AddEntityToObjectStateManager(IEntityWrapper wrappedEntity, Boolean doAttach) at...

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

This is my code in server which I try to run in a different task:

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

UnityManager给我一个包装DbContext的新类

The UnityManager gets me a new class that wrap the DbContext

推荐答案

您面临的问题是,您正在跨多个活动DbContext关联实体.通常,这意味着您拥有的DbContext认为已死&;处置,但没有.

The issue you are facing is that you are associating entities across multiple active DbContexts. This typically means that you have a DbContext that you think is dead & disposed, but isn't.

作为一个简单的例子:

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,将其状态设置为已修改",然后保存.

The above code works. We load an entity with one context, the context is disposed (end of using block) so the entity is now untracked. We can modify it, attach it to another DbContext, set its state to Modified, and save it.

现在采用以下代码:

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

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

This code is fairly similar, but note that the original context is not disposed. We load the entity and modify it, but then attempt to associate it to another context to save. We get the multiple entity change tracker exception.

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

The simple fix where you know the Context will not be disposed, and you definitely do need to associate the entity to a second context is to explicitly detach the entity from the original context:

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. (对于new建立的任何DbContext,using块)如果使用的是IoC容器,则需要了解它们如何将生存期作用域分配给所注入的依赖项.

However, in most cases this is merely hiding the underlying problem that you have DbContexts floating around that aren't getting disposed. The key here is to ensure that any DbContexts that are created are disposed. (using blocks for any DbContexts that are newed up) If you are using an IoC container then you need to read up on how they assign a lifetime scope to the dependencies they inject.

这篇关于实体框架6在多任务上失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆