代码之家  ›  专栏  ›  技术社区  ›  joshcomley

是否可以检查对象是否已附加到实体框架中的数据上下文?

  •  80
  • joshcomley  · 技术社区  · 15 年前

    尝试通过附加已附加到给定上下文的对象时,出现以下错误 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 回复  |  直到 7 年前
        1
  •  55
  •   joshcomley    15 年前

    以下是我最后得出的结论,效果非常好:

    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已经可以为我们这样做!).

        2
  •  40
  •   Mosh    11 年前

    更简单的方法是:

     bool isDetached = context.Entry(user).State == EntityState.Detached;
     if (isDetached)
         context.Users.Attach(user);
    
        3
  •  18
  •   jason    15 年前

    尝试此扩展方法(这是未经测试的,并且是现成的):

    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 key = new EntityKey("MyEntities.User", "Id", 1);
    

    你可以得到 实体密钥 来自的现有实例 User 通过使用属性 User.EntityKey (来自接口 IEntityWithKey )

        4
  •  6
  •   Daniel Elliott    15 年前

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

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

    仁慈,

        5
  •  0
  •   Lawrence    7 年前

    这并不能直接回答作战问题,但这就是我如何解决我的问题。

    这是给那些使用 DbContext 而不是 ObjectContext .

        public TEntity Retrieve(object primaryKey)
        {
            return DbSet.Find(primaryKey);
        }
    

    dbset.find方法 以下内容:

    查找具有给定主键值的实体。如果实体 给定的主键值存在于上下文中,然后 立即返回,无需向商店提出请求。否则, 为具有给定主实体的实体向存储发出请求 键值和此实体(如果找到)附加到上下文和 返回。如果在上下文或存储中找不到实体,则为空 返回。

    基本上,它返回给定的 primaryKey 所以您只需要对返回的对象应用更改,以保持正确的实例。