我正在使用实体框架来填充网格控件。有时当我进行更新时,我得到以下错误:

存储更新、插入或删除语句影响了意外的行数(0)。实体可能在加载实体后已被修改或删除。刷新ObjectStateManager条目。

我不知道怎么复制这个。但这可能和我更新的时间间隔有关系。有人见过这个吗,或者有人知道错误消息指的是什么吗?

编辑:不幸的是,我不再有自由重现我在这里遇到的问题,因为我离开了这个项目,不记得我最终是否找到了解决方案,是否有其他开发人员修复了它,或者是否我绕过了它。因此我不能接受任何回答。


当前回答

在从模型优先改为代码优先之后,我开始得到这个错误。我有多个线程更新数据库,其中一些可能更新同一行。我不知道为什么我没有使用模型优先的问题,假设它使用不同的并发默认。

为了在一个地方处理它,知道它可能发生的条件,我在DbContext类中添加了以下重载:

using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

public class MyDbContext: DbContext {
...
        public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
            try {
                return SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex) {
                foreach (DbEntityEntry entry in ex.Entries) {
                    if (refreshMode == RefreshMode.ClientWins)
                        entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                    else
                        entry.Reload();
                }
                return SaveChanges();
            }
        }
}

然后在任何适用的地方调用SaveChanges(true)。

其他回答

以上的答案都没有完全涵盖我的情况和解决方案。

在MVC5控制器中抛出错误的代码:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

当我从Edit视图保存对象时,我收到了这个异常。它抛出它的原因是,当我回去保存它时,我修改了构成对象主键的属性。因此,将其状态设置为Modified对EF没有任何意义——它是一个新条目,而不是先前保存的条目。

你可以通过以下两种方法来解决这个问题:A)修改save调用来添加对象;B)在edit时不要更改主键。B)。

当公认的答案说“它不会最终覆盖应用程序不知道已经发生的更改”时,我很怀疑,因为我的对象是新创建的。但后来发现,有一个INSTEAD OF UPDATE, INSERT- TRIGGER附加到表中,它正在更新同一表的计算列。

一旦我将其更改为AFTER INSERT, UPDATE,它就可以正常工作了。

这是乐观并发特性的副作用。

不是100%确定如何在实体框架中打开/关闭它,但基本上它告诉你的是,当你从数据库中获取数据时,当你保存你的更改时,其他人已经更改了数据(这意味着当你保存它时,0行实际上得到了更新)。在SQL术语中,它们的更新查询的where子句包含行中每个字段的原始值,如果0行受到影响,它就知道出错了。

它背后的思想是,你最终不会覆盖你的应用程序不知道发生了什么变化——它基本上是。net在所有更新中附带的一个小安全措施。

如果它是一致的,那么它很可能发生在您自己的逻辑中(例如:您实际上是在选择和更新之间的另一个方法中自己更新数据),但它可能只是两个应用程序之间的竞争条件。

您需要显式地包含主键的BoundField。如果你不想让用户看到主键,你必须通过css隐藏它:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

其中'hidden'是css中的一个类,它的显示设置为'none'。

    public void Save(object entity)
    {
        using (var transaction = Connection.BeginTransaction())
        {
        try
                {
                    SaveChanges();
                    transaction.Commit();
                }
                catch (OptimisticConcurrencyException)
                {
                    if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified)
                        this.Refresh(RefreshMode.StoreWins, entity);
                    else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added)
                        Detach(entity);
                    AcceptAllChanges(); 
                    transaction.Commit();
                }
        }
    }