尝试通过context.AttachTo(...)
附加已附加到给定上下文的对象时出现以下错误:
ObjectStateManager中已存在具有相同键的对象。 ObjectStateManager无法使用相同的键跟踪多个对象。
是否有办法实现以下目标:
context.IsAttachedTo(...)
干杯!
修改
Jason概述的扩展方法很接近,但它对我的情况不起作用。
我正在尝试使用另一个问题的答案中概述的方法做一些工作:
我的代码看起来有点像这样:
var user = new User() { Id = 1 };
context.AttachTo("Users", user);
comment.User = user;
context.SaveChanges();
这样可以正常工作,除非我为那个使用相同方法并试图附加虚拟User
对象的用户做了其他事情。这失败是因为我之前已经附加了这个虚拟用户对象。我该如何检查?
答案 0 :(得分:56)
这就是我最终得到的结果,效果非常好:
public static void AttachToOrGet<T>(this ObjectContext context, string entitySetName, ref T entity)
where T : IEntityWithKey
{
ObjectStateEntry entry;
// Track whether we need to perform an attach
bool attach = false;
if (
context.ObjectStateManager.TryGetObjectStateEntry
(
context.CreateEntityKey(entitySetName, entity),
out entry
)
)
{
// Re-attach if necessary
attach = entry.State == EntityState.Detached;
// Get the discovered entity to the ref
entity = (T)entry.Entity;
}
else
{
// Attach for the first time
attach = true;
}
if (attach)
context.AttachTo(entitySetName, entity);
}
您可以按如下方式调用它:
User user = new User() { Id = 1 };
II.AttachToOrGet<Users>("Users", ref user);
这很有效,因为它就像context.AttachTo(...)
,除了你可以使用我上面引用的ID技巧。您最终得到之前附加的对象或您自己的对象被附加。在上下文中调用CreateEntityKey
可以确保它很好并且通用,并且即使使用没有进一步编码的复合键也能工作(因为EF已经为我们做了!)。
答案 1 :(得分:42)
更简单的方法是:
bool isDetached = context.Entry(user).State == EntityState.Detached;
if (isDetached)
context.Users.Attach(user);
答案 2 :(得分:18)
尝试这种扩展方法(这是未经测试的,并且是袖手旁观的):
public static bool IsAttachedTo(this ObjectContext context, object entity) {
if(entity == null) {
throw new ArgumentNullException("entity");
}
ObjectStateEntry entry;
if(context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry)) {
return (entry.State != EntityState.Detached);
}
return false;
}
鉴于您在编辑中描述的情况,您可能需要使用以下重载来接受EntityKey
而不是对象:
public static bool IsAttachedTo(this ObjectContext, EntityKey key) {
if(key == null) {
throw new ArgumentNullException("key");
}
ObjectStateEntry entry;
if(context.ObjectStateManager.TryGetObjectStateEntry(key, out entry)) {
return (entry.State != EntityState.Detached);
}
return false;
}
要在您的情况下构建EntityKey
,请使用以下指南:
EntityKey key = new EntityKey("MyEntities.User", "Id", 1);
您可以使用属性EntityKey
(来自界面User
)从User.EntityKey
的现有实例获取IEntityWithKey
。
答案 3 :(得分:6)
使用您要检查的对象的实体键:
var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey");
if (entry.State == EntityState.Detached)
{
// Do Something
}
善,
丹
答案 4 :(得分:0)
这并没有直接回答OP问题,但这就是我解决问题的方法。
适用于使用DbContext
代替ObjectContext
的人。
public TEntity Retrieve(object primaryKey)
{
return DbSet.Find(primaryKey);
}
DbSet.Find方法:
查找具有给定主键值的实体。如果是实体 给定的主键值存在于上下文中,然后是 在没有向商店提出要求的情况下立即返回。除此以外, 向具有给定主要实体的实体的商店发出请求 键值和此实体(如果找到)附加到上下文和 回。如果在上下文或商店中找不到实体,则为null 归还。
基本上,它返回给定primaryKey
的附加对象,因此您只需对返回的对象应用更改以保留正确的实例。