实体框架:由于ObjectStateManager,使用ExecuteSqlCommand清除表会导致异常

时间:2012-10-23 14:43:04

标签: entity-framework ef-code-first

我使用的是EF5 Code First,需要一种快速清理表格的方法。因此我制作了一个非常简单的方法来使用ExecuteSqlCommand来提供快速表清除。代码如下:

    public void FastClearTable(Type tableType)
    {
        Context.Database.ExecuteSqlCommand(
            string.Format("delete from {0}", PluraliseTableName(tableType.Name)));
    }

我在重新计算之前使用它来清除表格。下面我列出了我的方法的简化版本。请注意,表的键是一个字符串(即不是标识键),所以我输入的新条目与ExecuteSqlCommand删除的条目具有相同的键。

public int ComputeNewTableContent( IRepository<MyClass> rep, IUnitOfWork uow)
{
     if ( rep.GetUntracked().Count() > 0)
           uow.FastClearTable( typeof(MyClass));

     --- compute new entries and call rep.Insert( newEntry) for each one ---
     uow.Commit();    //This calls DbContext.SaveChanges()
}

第一次运行正常但是如果我再次运行它会在SaveChanges()命令上得到一个异常,该命令由uow.Commit()调用。例外是:

Message =“调用目标已抛出异常。”

InnerException Message =“对数据库的更改已成功提交,但更新对象上下文时发生错误.ObjectContext可能处于不一致状态。内部异常消息: AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges 之前,请确保键值是唯一的。“

如果发现这个存档的MSDN post,并且在底部该人有同样的问题,但没有答案。我的观点是数据的内存版本仍然存在,并且不知道ExecuteSqlCommand。但是我还不知道EF还不知道如何解决它。

我当然可以通过使用“正常”删除来绕过它但我会很感激有人解释发生了什么以及如何处理它。这将提高我对实体框架的了解。

提前致谢。

2 个答案:

答案 0 :(得分:5)

我没有找到关于在实体框架中安全使用ExecuteSqlCommand的问题的一个很好的答案,直到我遇到了Julia Lerman的优秀书'Programming Entity Framework: DbContext'

她介绍了ExecuteSqlCommand的使用(第226页),但最重要的是,她提到在ExecuteSqlCommand之后使用 Reload 命令来更新本地(第138页)。这会从数据库中更新内存中实体。您可以按如下方式使用它:

    yourDbContext.Entry(TheTrackedEntityYouWantToUpdate).Reload();

这正是我所需要的。谢谢朱莉娅。

我认为Julia Lerman的DbContext书是任何计划使用Code First的真实应用程序的人必须的。

答案 1 :(得分:0)

您是否使用身份证明?可能是ObjectContext正在跟踪您从数据库中删除并添加新实体的旧实体。新实体(如果您没有密钥的标识列)将被赋予与旧实体相同的密钥。由于上下文已经跟踪旧实体,因此它获得具有被跟踪密钥的新实体。 EF假定所有更改都是通过对象上下文完成的,而不是来自数据库。如果你删除这样的实体,你应该扔掉上下文