是否可以检查对象是否已附加到Entity Framework中的数据上下文?

jos*_*ley 83 .net entity-framework

尝试通过以下方式附加已附加到给定上下文的对象时,我收到以下错误context.AttachTo(...):

ObjectStateManager中已存在具有相同键的对象.ObjectStateManager无法使用相同的键跟踪多个对象.

有没有办法实现以下方面:

context.IsAttachedTo(...)

干杯!

编辑:

Jason概述的扩展方法很接近,但它对我的情况不起作用.

我正在尝试使用另一个问题的答案中概述的方法做一些工作:

如何使用Linq to Entities*从表中删除一行或多行而不先检索行?

我的代码看起来有点像这样:

var user = new User() { Id = 1 };
context.AttachTo("Users", user);
comment.User = user;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

这工作正常,除非我为该用户执行其他操作,我使用相同的方法并尝试附加虚拟User对象.这失败是因为我之前已经附加了这个虚拟用户对象.我该如何检查?

jos*_*ley 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);
}
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式调用它:

User user = new User() { Id = 1 };
II.AttachToOrGet<Users>("Users", ref user);
Run Code Online (Sandbox Code Playgroud)

这很好用,因为context.AttachTo(...)除了你可以使用我上面引用的ID技巧之外.您最终得到之前附加的对象或您自己的对象被附加.调用CreateEntityKey上下文可以确保它很好并且通用,即使使用复合键也无需进一步编码(因为EF已经为我们做了!).

  • 当string参数被实体所属的集合的选择器函数替换时,会更好. (4认同)

Mos*_*osh 46

一种更简单的方法是:

 bool isDetached = context.Entry(user).State == EntityState.Detached;
 if (isDetached)
     context.Users.Attach(user);
Run Code Online (Sandbox Code Playgroud)

  • 嗯尝试了你的解决方案,但对我来说isDetached是真的,但当我尝试将条目附加到上下文时仍然是同样的错误 (18认同)
  • @Prokurors我最近了解到Mosh的检查并不总是足以防止错误的原因,当你调用`.Attach`或将其`EntityState`设置为`时,也会尝试附加`.Include()`'ed导航属性. `EntityState.Unchanged` - 如果任何实体引用同一个实体,它们将发生冲突.我还没弄清楚如何只附加基础实体,所以我不得不重新设计一下项目,为每个"业务事务"使用单独的上下文,就像它的设计目的一样.我会在未来的项目中注意到这一点. (4认同)

jas*_*son 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;
}
Run Code Online (Sandbox Code Playgroud)

鉴于您在编辑中描述的情况,您可能需要使用以下重载来接受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;
}
Run Code Online (Sandbox Code Playgroud)

要构建适合EntityKey您的情况,请使用以下指南:

EntityKey key = new EntityKey("MyEntities.User", "Id", 1);
Run Code Online (Sandbox Code Playgroud)

您可以使用属性(来自接口)EntityKey从现有实例获取.UserUser.EntityKeyIEntityWithKey


Dan*_*ott 6

使用您要检查的对象的实体键:

var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey");
if (entry.State == EntityState.Detached)
{
  // Do Something
}
Run Code Online (Sandbox Code Playgroud)

善良,