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

时间:2009-11-11 14:27:38

标签: .net entity-framework

尝试通过context.AttachTo(...)附加已附加到给定上下文的对象时出现以下错误:

  

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

是否有办法实现以下目标:

context.IsAttachedTo(...)

干杯!

修改

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

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

How do I delete one or more rows from my table using Linq to Entities *without* retrieving the rows first?

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

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

这样可以正常工作,除非我为那个使用相同方法并试图附加虚拟User对象的用户做了其他事情。这失败是因为我之前已经附加了这个虚拟用户对象。我该如何检查?

5 个答案:

答案 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的附加对象,因此您只需对返回的对象应用更改以保留正确的实例。