【问题标题】:The object cannot be deleted because it was not found in the ObjectStateManager无法删除该对象,因为它在 ObjectStateManager 中找不到
【发布时间】:2021-12-07 10:34:27
【问题描述】:

我收到此错误“无法删除该对象,因为在 ObjectStateManager 中找不到它。”

我的代码是:

    protected MyEntities sqlEntities;

    public virtual void Delete(TEntity entity)
    {
        System.Type t = typeof(TEntity);
        sqlEntities.DeleteObject(entity);
        sqlEntities.SaveChanges();
    }

【问题讨论】:

  • 抱歉代码中出现了使用不同的datacontext对象来获取和删除记录的问题。
  • 我遇到了这样的错误:var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity); 我试图创建一个正确设置 PK 的模拟实体,希望实体框架会根据 PK 调用 DeleteObject

标签: c# asp.net entity-framework-4


【解决方案1】:

这意味着实体没有附加(它不是由同一个上下文实例加载的)。试试这个:

protected MyEntities sqlEntities;

public virtual void Delete(TEntity entity)
{
    sqlEntities.Attach(entity);
    sqlEntities.DeleteObject(entity);
    sqlEntities.SaveChanges();
}

【讨论】:

  • 谢谢拉迪斯拉夫。当我在从父级删除子数据时发生两个上下文时,这对我有帮助 - 这是从 TransactionScope 之外的不同上下文调用的。将父调用移到范围和相同的上下文中,我的问题就解决了。
  • @Ladislav:如果我使用 .Attach,我会得到一个不同的错误:“一个实体对象不能被多个 IEntityChangeTracker 实例引用。”这是否意味着已经有其他对象实例在阻止删除?
  • @Matt:不,这意味着您的对象已经附加到另一个上下文。它不能同时连接到两个。您应该使用原始上下文来删除实体。
  • @Ladislav:谢谢,这帮助我进一步了解 - 我发现这个问题似乎可以回答如何解决它:Is is possible to check if an object is already attached to a data context in Entity Framework?。你是对的,这似乎是我的问题。感谢您的快速回答!
  • 谢谢提醒,我刚更新记录的时候附上了,删除记录的时候没有附上。
【解决方案2】:

只是对the answer by Ladislav Mrnka 的一个小说明(这应该是公认的答案)。

如果你和我一样,你的代码格式如下:

using (var context = new MyDataContext())
{
    context.MyTableEntity.Remove(EntytyToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

..那么这就是你想要做的:

using (var context = new MyDataContext())
{
    // Note: Attatch to the entity:
    context.MyTableEntity.Attach(EntityToRemove);

    context.MyTableEntity.Remove(EntityToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

也许这似乎很明显,但我最初并不清楚是否有必要指定要附加到的 entity,而不仅仅是 context

【讨论】:

  • 我使用这种方法并收到异常:“存储更新、插入或删除语句影响了意外数量的行 (0)。自加载实体后,实体可能已被修改或删除。刷新 ObjectStateManager 条目。”
【解决方案3】:

只是为了解释 Kjartans 的解释:

我有:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = GetProject(id);
            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }

问题是我使用自己的方法(GetProject())来获取实体(因此使用另一个上下文来加载实体):

public Project GetProject(int id)
    {
        using (var context = new Context())
        {
            var project = context.Projects
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Profession)))
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Room)))
                .SingleOrDefault(x => x.Id == id);
            return project;      
        }
    }

一种解决方案可能是按照 Kjartan 的说明附加加载的实体,另一种可能是我的解决方案,在相同的上下文中加载实体:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = context.Projects.SingleOrDefault(x => x.Id == id);
            if (p == null)
                return p;

            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }

【讨论】:

    【解决方案4】:

    我知道这个问题已经很老了,但以上都对我没有用,因为我从多个类/服务中删除了寄存器,并且它们中的每一个都在实例化它自己的数据库连接上下文。

    我为解决这个问题所做的是将第一个创建的上下文发送到要访问数据库的其余类/服务。

    例如,我的serviceA 将删除它的一些寄存器并调用serviceBserviceC 对它们的寄存器执行相同的操作。

    然后我会删除我在serviceA 上的寄存器,并将在serviceA 上创建的上下文作为参数传递给serviceBserviceC

    【讨论】:

      【解决方案5】:

      你可以写这个代码:

      var x=yourquery.FirstOrDefault(); 
      
      sqlEntities.DeleteObject(x);
      sqlEntities.SaveChanges();
      

      【讨论】:

        【解决方案6】:

        如果上述方法都不起作用,您可以尝试以下解决方案:

        context.Entry(yourObject).State = System.Data.Entity.EntityState.Deleted; context.SaveChanges();

        【讨论】:

          【解决方案7】:

          您应该确保您的对象存在于您要从中删除的列表中, 您应该提出以下条件

          if(context.entity.contains(你的对象))

          删除它。

          如果你有一个复杂的相等条件你应该覆盖 实体类中的 equal 方法 设置相等条件, 为扩展方法 "entity.contains"

          找到正确的方法

          【讨论】:

            【解决方案8】:

            确保传入 Remove(Entity) 的模型与数据库记录完全相同。

            有时它可以传递模型而没有一些字段,如 Id 或 Date。如果您以表单形式发布,请将它们保留在 @html.Hiddenfor 中。

            最好的方法是传递 ID 并使用 Find(Id) 方法获取实体并将其传递给 Remove(Entity)

            希望这对某人有所帮助。

            【讨论】:

              【解决方案9】:

              我遇到了这个问题并解决了。只需复制以下代码:

              sqlEntities.Attach(entity);
              sqlEntities.Remove(entity);
              sqlEntities.SaveChanges();
              

              【讨论】:

                【解决方案10】:

                在我的情况下,只有一个上下文,但我得到了带有“AsNoTracking”选项的实体

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-10-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多