首页 文章

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

提问于
浏览
286

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

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

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

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

30 回答

  • 9

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

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

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

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

  • 3

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

    来自Paul Bellora的评论

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

  • 1

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

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

    MyObject foo = new MyObject()
    {
        someAttribute = someValue
    };
    
    context.Entry(foo).State = EntityState.Modified;
    context.SaveChanges();
    

    是的,这似乎是愚蠢的,但它的出现是因为有问题的方法曾经在之前创建了 foo 传递给它,现在它只传递了 someValue 并创建 foo 本身 .

    轻松修复,只需将 EntityState.Modified 更改为 EntityState.Added 或将整行更改为:

    context.MyObject.Add(foo);
    
  • 7

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

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

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

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

  • 22

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

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

  • 2

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

    • 您尝试更新具有一个或多个属性的行 Concurrency Mode: Fixed ..并且Optimistic Concurrency阻止了数据的保存 . IE浏览器 . 有些人在收到服务器数据和保存服务器数据之间更改了行数据 .

    • 您试图更新或删除一行,但该行没有让我们试图更新一个不是Identity的字段(即 StoreGeneratedPattern = Computed )并且该行不存在 .

  • 3

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

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

  • 362

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

    我的模型使用实体's ID which was causing the value of the entity'的ID上的 Bind(Exclude) 属性在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; }
        }
    }
    
  • 3

    我有同样的问题,我发现这是由RowVersion引起的,它是null . 检查你的 Id 和你的 RowVersionnot null .

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

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

  • 10

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

    @Html.HiddenFor(m => m.Id)
    

    解决了这个问题 .

    此外,如果您的模型包括非使用项目也包括那个并将其发布到调节器

  • 2

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

  • 7

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

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

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

  • 5

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

    为了在一个地方处理它,知道它可能发生的条件,我在我的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) .

  • 16
    @Html.HiddenFor(model => model.RowVersion)
    

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

  • 8

    在我的案例中, [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)] 行就是这样做的:

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int? SomeNumber { get; set; }
    
  • 15

    Just make sure table and form both have primary key and edmx updated.

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

  • 5

    使用 async 方法时偶尔会出现此错误 . 自从我切换到同步方法以来没有发生过 .

    偶尔出错:

    [Authorize(Roles = "Admin")]
    [HttpDelete]
    [Route("file/{id}/{customerId}/")]
    public async Task<IHttpActionResult> Delete(int id, int customerId)
    {
        var file = new Models.File() { Id = id, CustomerId = customerId };
        db.Files.Attach(file);
        db.Files.Remove(file);
    
        await db.SaveChangesAsync();
    
        return Ok();
    }
    

    一直工作:

    [Authorize(Roles = "Admin")]
    [HttpDelete]
    [Route("file/{id}/{customerId}/")]
    public IHttpActionResult Delete(int id, int customerId)
    {
        var file = new Models.File() { Id = id, CustomerId = customerId };
        db.Files.Attach(file);
        db.Files.Remove(file);
    
        db.SaveChanges();
    
        return Ok();
    }
    
  • 2

    当我删除DB中的某些行(在循环中)并在同一个表中添加新行时,我收到了该错误 .

    对我来说,解决方案是动态地在每个循环迭代中创建一个新的上下文

  • 4
    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();
                    }
            }
        }
    
  • 6

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

    去做这个:

    if (ModelState.IsValid)
    {
    context.Entry(yourModelReference).State = EntityState.Added;
    context.SaveChanges();
    }
    

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

    希望这可以帮助 .

  • 2

    我有同样的问题 . 在我的情况下,我试图更新主键,这是不允许的 .

  • 5

    如果您尝试在edmx文件中创建映射到“函数Imports”,则可能导致此错误 . 只需清除edmx中给定实体的映射详细信息中的插入,更新和删除字段,它就可以正常工作 . 我希望我说清楚 .

  • 2

    如果您试图插入一个独特的约束情况,也就是说如果您每个雇主只能有一种类型的地址,并且您尝试在同一雇主中插入同一类型的第二种类型,那么您也会遇到同样的问题 .

    OR

    如果分配给所有对象属性,也可能会发生这种情况,它们被分配了与之前相同的值 .

    using(var db = new MyContext())
            {
                var address = db.Addresses.FirstOrDefault(x => x.Id == Id);
    
                address.StreetAddress = StreetAddress; // if you are assigning   
                address.City = City;                   // all of the same values
                address.State = State;                 // as they are
                address.ZipCode = ZipCode;             // in the database    
    
                db.SaveChanges();           // Then this will throw that exception
            }
    
  • 3

    我有同样的问题 . 但这是由于我自己的错误 . 实际上我正在保存一个对象而不是添加它 . 所以这就是冲突 .

  • 4

    在Sql Server环境中调试此问题的一种方法是使用SqlServer副本中包含的Sql Profiler,或者如果使用Express版本,请通过以下链接从CodePlex免费获取Express Profiler的副本:

    Express Profiler

    通过使用Sql Profiler,您可以访问EF发送给数据库的任何内容 . 在我的情况下,这相当于:

    exec sp_executesql N'UPDATE [dbo].[Category]
    SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3
    WHERE ([CategoryID] = @4)
    ',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier',
    @0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09',
    @3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778'
    go
    

    我将其复制粘贴到Sql Server的查询窗口中并执行它 . 果然,虽然它运行了,但是这个查询影响了0条记录,因此EF返回了错误 .

    在我的情况下,问题是由CategoryID引起的 .

    发送到数据库的ID EF没有识别出CategoryID,因此0个记录受到影响 .

    这不是EF的错,而是一个错误的空合并“??”在View Controller中声明向无意义发送到数据层 .

  • 2

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

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

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

    我在“编辑”视图中保存对象时收到此异常 . 它抛出它的原因是因为当我回去保存它时,我修改了在对象上形成主键的属性 . 因此,将其状态设置为Modified对EF没有任何意义 - 它是一个新条目,而不是以前保存的条目 .

    您可以通过以下方法解决此问题:A)修改保存调用以添加对象,或者B)只是在编辑时不更改主键 . 我做了B) .

  • 1

    当接受的答案说“ it won't end up overwriting a change that your application didn't know has happened ”时,我怀疑是因为我的对象是新创建的 . 但事实证明,有一个 INSTEAD OF UPDATE, INSERT- TRIGGER 附加到正在更新同一个表的计算列的表中 .

    一旦我将其更改为 AFTER INSERT, UPDATE ,它工作正常 .

  • 96

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

  • 2

    我使用Telerik的RadGrid遇到了这个问题 . 我将主键作为网格列设置为只读 . 如果列是display =“false”,但readonly =“true”导致问题,它将正常工作 . 我通过使gridbound列display = false并添加一个单独的模板列来显示来解决它

    <telerik:GridBoundColumn HeaderText="Shouldnt see" Display="false" 
         UniqueName="Id" DataField="Id">
    </telerik:GridBoundColumn>
    <telerik:GridTemplateColumn HeaderText="Id" UniqueName="IdDisplay">
        <ItemTemplate>
            <asp:Label ID="IDLabel" runat="server" 
                Text='<%# Eval("Id") %>'></asp:Label>                               
        </ItemTemplate>
    </telerik:GridTemplateColumn>
    
  • 180

    附加数据库中不存在的对象时出现此异常 . 我假设对象是从单独的上下文加载的,但如果是用户第一次访问该站点,则该对象是从头开始创建的 . 我们有自动递增的主键,所以我可以替换

    context.Users.Attach(orderer);
    

    if (orderer.Id > 0) {
        context.Users.Attach(orderer);
    }
    

相关问题