实体框架:"存储更新,插入或删除语句影响了意外的行数(0)."

str*_*ons 312 entity-framework

我正在使用Entity Framework来填充网格控件.有时当我进行更新时,我收到以下错误:

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

我无法弄清楚如何重现这一点.但它可能与我进行更新的距离有多大关系.有没有人看过这个或有没有人知道错误信息是指什么?

编辑:不幸的是我不再自由地重现我在这里遇到的问题,因为我离开了这个项目并且不记得我是否最终找到了解决方案,如果另一个开发人员修复它,或者我是否解决了这个问题.因此我不能接受任何答案.

小智 385

我遇到了这个问题,这是由实体的ID(密钥)字段未设置引起的.因此,当上下文保存数据时,它找不到ID = 0.确保在update语句中放置一个断点并验证是否已设置实体的ID.

来自Paul Bellora的评论

我有这个确切的问题,因为忘记在.cshtml编辑页面中包含隐藏的ID输入

  • +1感谢您添加此答案 - 我有一个确切的问题,因为忘记在.cshtml编辑页面中包含隐藏的ID输入. (72认同)
  • @ Html.HiddenFor(model => model.productID) - 工作完美.我错过了编辑页面上的productID(MVC RAZOR) (4认同)
  • +1我遇到了同样的问题,这有助于找到解决方案.事实证明我的订单模型中有[Bind(Exclude ="OrderID")],这导致实体ID的值在HttpPost上为零. (3认同)
  • 这正是我所缺少的.我的对象的ID是0. (2认同)
  • 我有一个类似的问题,但有一个扭曲.对我来说问题是我没有正确设置sql表.我的主键字段未设置为自动增量.因此EF会发送我试图插入w/o键的记录,如果你记得告诉sql该字段是一个自动增量标识字段,我忘了:< (2认同)

fyj*_*ham 195

这是一种称为乐观并发的功能的副作用.

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

它背后的想法是你不会最终覆盖你的应用程序不知道发生的变化 - 这基本上是.NET在你所有更新中引入的一点安全措施.

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

  • 这发生在单用户环境中(在我的开发机器上),所以我认为这不是一个竞争条件.我绑定到一个带有EntityDataSource的自定义网格控件,所以我不确定幕后发生了什么,但我没有任何额外的代码来修改表格.有没有办法改变这种并发设置? (34认同)
  • 如果实体具有时间戳属性,请确保将其存储在视图中,并确保实体正确填充时间戳. (8认同)
  • 我认为你可以在你的实体模型中按列进行(它在属性窗口中),但问题是,它只会阻止你看到错误并且它仍然不会更新任何东西.您是否能够查看进入数据库的SQL命令(EG:SQL Server Profiler for MSSQL)?通过这种方式,您可以查看生成的更新内容,并且应该能够了解更新不会影响任何行的原因. (3认同)
  • 如果使用时间戳,则要删除的对象需要PK集和RowVersion属性才能成功更新!在将对象附加到相应的DbSet之后,我设置了rowVersion(timestamp)属性,这就是为什么它不起作用.做得好! (2认同)

Ben*_*Ben 109

哇,很多答案,但是当我做了一些稍微不同的事情时,我得到了这个错误.

简而言之,如果你创建一个新对象并告诉EF它使用它修改EntityState.Modified它然后会抛出这个错误,因为它在数据库中还不存在.这是我的代码:

MyObject foo = new MyObject()
{
    someAttribute = someValue
};

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

是的,这看起来很愚蠢,但它之所以产生,是因为foo之前已经创建的问题已经传递给它,现在它只someValue传递给它并创建foo自己.

简单的办法,只是改变EntityState.ModifiedEntityState.Added或全行更改为:

context.MyObject.Add(foo);
Run Code Online (Sandbox Code Playgroud)


Len*_*rri 23

我面对同样的惊吓错误...... :)然后我意识到我忘了设置一个

@Html.HiddenFor(model => model.UserProfile.UserId)

对于正在更新的对象的主键!我倾向于忘记这个简单但非常重要的东西!

顺便说一下:HiddenFor适用于ASP.NET MVC.

  • 这似乎是一个安全漏洞,将"UserId"存储在表单中,非常容易出现黑客......这应该是从"HttpContext.Current.User.Identity.Name"填充的. (3认同)
  • 我的观点是,为什么即使将其存储在“HiddenFor”中,您仍然需要从“HttpContext”中获取它...我根本不会将此属性放入表单中,这将迫使我始终在服务器端填充它... (2认同)

小智 16

检查您是否忘记了GridView中的"DataKeyNames"属性.在GridView中修改数据时必须使用它

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx


Pur*_*ome 15

问题是由以下两种情况之一引起的: -

  1. 您尝试更新具有一个或多个属性的行Concurrency Mode: Fixed..并且Optimistic Concurrency阻止了数据的保存.IE浏览器.有些人在收到服务器数据和保存服务器数据之间更改了行数据.
  2. 您尝试更新或删除行但该行不存在.有人在检索之间更改数据(在这种情况下,删除)的另一个例子然后保存或者我们试图更新不是标识的字段(即.StoreGeneratedPattern = Computed)并且该行不存在.


inn*_*227 11

我得到了同样的错误,因为PK的一部分是一个日期时间列,并且插入的记录使用DateTime.Now作为该列的值.实体框架将以毫秒精度插入值,然后以毫秒精度查找刚刚插入的值.但是,SqlServer将该值四舍五入为第二精度,因此实体框架无法找到毫秒精度值.

解决方案是在插入之前截断DateTime.Now的毫秒数.

  • 除了我们使用`DateTime`值插入`Date`列之外,我们遇到了同样的问题 (2认同)

Dha*_*ust 9

我有同样的问题,@ webtrifusion的答案帮助找到了解决方案.

我的模型使用了Bind(Exclude)实体ID 的属性,该属性导致实体ID的值在HttpPost上为零.

namespace OrderUp.Models
{
[Bind(Exclude = "OrderID")]
public class Order
{
    [ScaffoldColumn(false)]
    public int OrderID { get; set; }

    [ScaffoldColumn(false)]
    public System.DateTime OrderDate { get; set; }

    [Required(ErrorMessage = "Name is required")]
    public string Username { get; set; }
    }
}   
Run Code Online (Sandbox Code Playgroud)


Bil*_*adi 9

我有同样的问题,我发现这是由RowVersion引起的,它是null.检查您的IdRowVersion是否为.

有关更多信息,请参阅本教程

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application


小智 7

编辑时将实体的id或主键包含在视图中作为隐藏字段

      @Html.HiddenFor(m => m.Id)
Run Code Online (Sandbox Code Playgroud)

解决了这个问题.

此外,如果您的模型包括未使用的项目也包括它并将其发布到控制器


Si-*_*i-N 7

我也遇到了这个错误.它的问题是由我试图保存到的表上的触发器引起的.触发器使用'INSTEAD OF INSERT',这意味着有0行插入到该表中,因此出错.幸运的是,触发器功能可能不正确,但我想这可能是一个有效的操作,应该以某种方式在代码中处理.希望这有一天可以帮助某人.

  • 可以通过从触发器返回SELECT语句(使用主键列)来欺骗实体,使其相信行已添加. (2认同)
  • 为了扩展 @jahu 的评论,我必须获取要从触发器返回的新插入项目的实际 id,并且列名称必须与触发器表的标识列匹配(在我的例子中,实际上是一个视图,所以它没有没有自己的身份,但我欺骗了 edmx 相信它有)。我的触发器正在插入到一个单独的表中,所以我只是将最后一行添加到我的触发器中:`SELECT SCOPE_IDENTITY() as MyViewId` (2认同)

ave*_*ore 7

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

为了在一个地方处理它,知道它可能发生的条件,我在我的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();
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

然后SaveChanges(true)在适用的地方打电话.


Pau*_*ulo 6

您需要明确包含主键的BoundField.如果您不希望用户看到主键,则必须通过css将其隐藏:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />
Run Code Online (Sandbox Code Playgroud)

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


com*_*tc2 6

我在一个缺少主键并且有一个 DATETIME(2, 3) 列的表上遇到了这个问题(所以实体的“主键”是所有列的组合)......执行插入时时间戳有更精确的时间 (2018-03-20 08:29:51.8319154) 被截断为 (2018-03-20 08:29:51.832) 因此关键字段的查找失败。


Moj*_*oji 5

只需确保表和表单都有主键和 edmx 更新。

我发现更新期间的任何错误通常是因为: - 表中没有主键 - 编辑视图/表单中没有主键(例如@Html.HiddenFor(m=>m.Id


Rus*_*ail 5

我也有这个错误。在某些情况下,实体可能不知道您正在使用的实际数据库上下文,或者模型可能不同。为此,设置:EntityState.Modified; 到 EntityState.Added;

去做这个:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

这将确保实体知道您正在使用或添加您正在使用的状态。此时需要设置所有正确的模型值。小心不要丢失可能在后台进行的任何更改。

希望这可以帮助。


Pra*_*h R 5

  @Html.HiddenFor(model => model.RowVersion)
Run Code Online (Sandbox Code Playgroud)

我的rowversion为null,因此不得不将其添加到解决了我的问题的视图中


Tom*_*omo 5

[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]在我的案例中,这条线就行了:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }
Run Code Online (Sandbox Code Playgroud)