无法删除该对象,因为在ObjectStateManager中找不到该对象


114

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

我的代码是:

    protected MyEntities sqlEntities;

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

5
抱歉,代码中存在一个问题,即使用不同的datacontext对象来获取和删除记录。
萨米(Sami)

我有一个像这样的错误:var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);我试图创建一个正确设置其PK的模拟实体,希望实体框架将根据PK
C

Answers:


156

这意味着未附加实体(同一上下文实例未加载该实体)。试试这个:

protected MyEntities sqlEntities;

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

1
谢谢拉迪斯拉夫。当从父级删除子级数据时发生两个上下文时,这对我有帮助-从另一个上下文在TransactionScope之外调用该数据。将父调用移到范围和相同上下文内,我的问题就解决了。
dan richardson

1
@Ladislav:如果我使用.Attach,则会收到另一个错误:“一个IEntityChangeTracker的多个实例无法引用一个实体对象。” 这是否意味着已经存在其他阻止删除的对象实例?
马特

2
@Matt:不,这意味着您的对象已经附加到另一个上下文。它不能同时连接到两个。您应该使用原始上下文删除实体。
Ladislav Mrnka

@Ladislav:谢谢,这帮助我进一步了解了-我发现了一个似乎可以回答该问题的问题:是否可以检查对象是否已连接到实体框架的数据上下文中?。没错,这似乎是我的问题。感谢您及时回复!
马特

感谢您的提醒,我只是在更新记录时附加了它,但在删除记录时却没有附加。
pinmonkeyiii

60

只是对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();
}

也许这似乎很明显,但最初对我而言尚不清楚,有必要指定要访问的实体,而不仅仅是上下文


1
我使用这种方法并收到异常:“存储更新,插入或删除语句影响了意外的行数(0)。自从加载实体以来,实体可能已被修改或删除。刷新ObjectStateManager条目。”
kat1330

11

只是为了解释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;
        }
    }

2

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

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

例如,我serviceA打算删除其中的某些寄存器并调用serviceBserviceC对其寄存器进行相同操作。

然后,我将删除我的寄存器,serviceA并将在serviceAto serviceB和上创建的上下文作为参数传递serviceC


2

您可以编写以下代码:

var x=yourquery.FirstOrDefault(); 

sqlEntities.DeleteObject(x);
sqlEntities.SaveChanges();


0

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

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

去掉它。

如果具有复杂的相等条件,则应在实体类中重写equal方法以放置相等条件,以获取扩展方法“ entity.contains”的正确方法


0

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

有时可能会通过没有某些字段(例如Id或Date)来传递模型。如果您以表单形式发布,请将其保存在@ html.Hiddenfor中。

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

希望这对某人有帮助。


0

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

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

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.