我正在使用 EF 5.0 创建一个网络,但在处理我的上下文时遇到了一些问题。我使用上下文的所有时间都在使用语句中,因此应该自动处理上下文,但是在特定时刻,当我尝试将实体附加到上下文时,会出现下一个错误:
ObjectStateManager 中已存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
看来该实体没有被处置。如何处理这种情况?我是否必须处置 ObjectContext 才能处置实体,或者有什么方法可以检查实体是否已附加?
问候。
我正在使用 EF 5.0 创建一个网络,但在处理我的上下文时遇到了一些问题。我使用上下文的所有时间都在使用语句中,因此应该自动处理上下文,但是在特定时刻,当我尝试将实体附加到上下文时,会出现下一个错误:
ObjectStateManager 中已存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
看来该实体没有被处置。如何处理这种情况?我是否必须处置 ObjectContext 才能处置实体,或者有什么方法可以检查实体是否已附加?
问候。
一种方法是在附加之前分离现有对象。我面前没有 VS,所以如果代码不完全正确,我深表歉意。
var existingObject = dbContext.Users.Local
.FirstOrDefault(x => x.id = newObject.id);
if (existingObject != null)
{
// remove object from local cache
dbContext.Entry(existingObject).State = EntityState.Detached;
}
dbContext.Users.Attach(newObject);
如果这不能解决问题,您将不得不采用分离对象的旧方法。
// remove object from local cache
ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
objectContext.Detach(existingObject);
Dispose
并不意味着“恢复出厂设置”。这是一种清理非托管资源(如数据库连接等)的方法。
这个问题与是否处理上下文无关。它甚至与在某个地方拥有多个上下文无关。如果这是问题所在,您将得到“一个实体对象不能被多个 IEntityChangeTracker 实例引用”异常,这与您的异常完全不同。
您可以仅使用一个上下文非常轻松地模拟您的异常:
using (var ctx = new MyContext())
{
var customer1 = new Customer { Id = 1 };
var customer2 = new Customer { Id = 1 }; // a second object with the same key
ctx.Customer.Attach(customer1);
ctx.Customer.Attach(customer2); // your exception will occur here
}
导致此异常的问题通常更隐蔽,特别是如果您记住附加或设置状态(例如 to Modified
)也会在您附加的实体的对象图中附加所有相关实体。如果在此图中是两个具有相同键的对象,您也会得到异常,尽管您没有明确附加这些相关实体。
但是,如果没有有关您的代码的更多详细信息,就不可能找到确切的原因。
如果你这样做:
User u;
using (Entities ent = new Entities())
{
u = ent.Users.Single(a => a.ID == 123);
}
using (Entities ent2 = new Entities())
{
//loading the same user
User user2 = ent2.Users.Single(a => a.ID == 123);
//trying to attach the same object with the same key
ent2.Attach(u);
}
那么你会得到这个错误(我没有测试过这段代码)。
编辑:解决方案之一是更改对象的状态:
ent2.Attach(u);
ent2.ObjectStateManager.ChangeObjectState(u, EntityState.Modified);
另一种解决方案是检查实体是否已附加:
ObjectStateEntry state = null;
if(!ent2.ObjectStateManager.TryGetObjectStateEntry(((IEntityWithKey)u).EntityKey, out state))
{
ent2.Attach(u);
}