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


324

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

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

我不知道如何重现这一点。但这可能与我进行更新的紧密程度有关。是否有人看到过此消息,或者有人知道错误消息指的是什么?

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


我由于引入SQL Server行级安全性策略而收到此错误,该策略允许将行更新到无法回读的状态(具有允许的BLOCK谓词的排他FILTER谓词)。EntityFramework要求在更新后重新读取更新的行,否则它假定这是并发错误(至少在使用乐观并发时)。
xr280xr

这个问题可能是不正确的作用域为您的DbContext stackoverflow.com/questions/49154250/...(本例中是ASPNET身份,但适用于任何环境)
Simon_Weaver

不管此错误的上下文如何,都最好在实例化上下文的任何地方放置一个断点。您是否希望在加载网页时实例化一次,但是该中断点达到该断点5次?那么您可能有比赛条件。查看Request.Uri以查看实际的请求URL。在我的情况下,我有一些跟踪逻辑正在访问我的站点,并不必要地从数据库中加载了上下文(偶尔也对其进行了更新)。因此,我正在调试的实际页面被愚蠢的跟踪代码逻辑所占用。
Simon_Weaver

在视图中添加@ Html.AntiForgeryToken()
Vikas Sharma

Answers:


199

这就是所谓的乐观并发功能的副作用。

不能100%确定如何在Entity Framework中打开/关闭它,但是基本上它告诉您的是,从数据库中获取数据到保存更改之间,其他人更改了数据(这意味着您去了将其保存为0行实际上已更新)。用SQL术语来说,他们的update查询where子句包含该行中每个字段的原始值,如果0行受到影响,它就知道出了问题。

其背后的想法是,您最终不会覆盖应用程序不知道发生的更改-这基本上是.NET在所有更新上引发的一点安全措施。

如果一致,则很可能是在您自己的逻辑内发生的(EG:您实际上是在select和update之间使用另一种方法来更新数据),但这可能只是两个应用程序之间的竞争条件。


34
这是在单用户环境(在我的开发机上)上发生的,因此我认为这可能不是竞争条件。我将绑定到带有EntityDataSource的自定义网格控件,因此我不确定幕后到底发生了什么,但是我自己没有修改表的任何额外代码。有没有办法更改此并发设置?
strongopinions

3
我认为您可以在实体模型的每个列中(它位于属性窗口中),但是事实是,这只会防止您看到错误,并且仍然不会更新任何内容。您是否能够查看发送到数据库的SQL命令(例如:MSSQL的SQL Server Profiler)?这样,您可以看到它生成了什么更新,并且应该能够看到为什么该更新不影响任何行。
fyjham

9
如果实体具有timestamp属性,请确保已将其存储在视图中,并确保实体正确填充了时间戳。
2013年

我有一本时间戳记专栏,一经解决,EF6.1即可按预期工作,感谢提示@anelBMer
JQII 2014年

3
如果使用时间戳记,则要删除的对象需要PK集和RowVersion属性才能成功更新!在将对象附加到相应的DbSet之后,我设置了rowVersion(timestamp)属性,这就是为什么它不起作用的原因。做得好!
传说

394

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

来自Paul Bellora的评论

我遇到了这个确切的问题,是由于忘记在.cshtml编辑页面中包含隐藏的ID输入而导致的


3
+1我遇到了同样的问题,这有助于找到解决方案。原来我的Order模型中有[Bind(Exclude =“ OrderID”)),这导致HttpPost上的实体ID的值为零。
Dhaust 2012年

2
那正是我所缺少的。我对象的ID为0
爱资哈尔Khorasany

4
@ Html.HiddenFor(model => model.productID)-工作完美。我在编辑页面(MVC RAZOR)上缺少productID
Ravi Ram

2
我有一个类似的问题,但有一个转折。对我来说,问题是我没有正确设置sql表。我的主键字段未设置为自动递增。因此,EF将发送我尝试插入w / oa键的记录,如果您记得告诉sql该字段是一个自动递增的Identity字段,那我就忘了:<
Agile Noob

1
同样的问题,但使用组合键。未设置键值之一。
obaylis 2015年

113

哇,有很多答案,但是当我做了一些与众不同的事情时,我遇到了这个错误。

长话短说,如果您创建一个新对象并告诉EF使用对其进行了修改,EntityState.Modified则它将抛出此错误,因为它在数据库中尚不存在。这是我的代码:

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

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();

是的,这似乎很愚蠢,但是出现的原因是,该方法以前是foo通过传递给它的方法创建的,而现在只是someValue传递给它并创建foo自己。

易于修复,只需更改EntityState.ModifiedEntityState.Added或将整个行更改为:

context.MyObject.Add(foo);

感谢您发布此信息。这也是我的问题,我复制粘贴了一些将State设置为EntityState.Modified的代码。
clayRay

23

我正面临着同样的令人恐惧的错误... :)然后我意识到我忘记了设置一个

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

用于更新对象的主键!我倾向于忘记这个简单但非常重要的事情!

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


3
这似乎是一个安全漏洞,将其存储为UserId格式,非常容易受到黑客攻击……此后应填充HttpContext.Current.User.Identity.Name
Serj Sagan

@SerjSagan您是对的...但是只要您在服务器端进行一些检查以确认您可以使用UserId和当前UserName。
Leniel Maccaferri

1
我的观点是为什么即使将其存储在HiddenFor您中也HttpContext无论如何都需要获取它...我根本不会将该属性放在表单中,这将迫使我始终在服务器端填充它...
Serj Sagan

16

检查是否忘记了GridView中的“ DataKeyNames”属性。在GridView中修改数据时这是必须的

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


+1。对我来说完美而简单的解决方案。我将GridView绑定到EntityDataSource,并且未将此设置为对象的主键。
安德斯(Andez)2012年

我们知道Kendo UI不支持组合键,但是如果我添加了新列来将我的键连成一列,那又是怎么回事?
Branislav

15

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

  1. 您尝试使用一个或多个属性更新行 Concurrency Mode: Fixed ..并且Optimistic Concurrency阻止保存数据。就是 在收到服务器数据到保存服务器数据之间,有些更改了行数据。
  2. 您尝试更新或删除行,但该行不存在。另一个在检索然后保存之间更改数据(在本例中为删除)的示例,或者您正在尝试更新不是身份(即StoreGeneratedPattern = Computed)且该行不存在的字段。

1
如果为所有分配给它们的对象属性分配了与以前相同的值,也可能导致这种情况。
Serj Sagan

+1为第二个。我让StoreGeneratedPattern = None,更改为StoreGeneratedPattern = Identity解决了该问题。谢谢
tkt986

12

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

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


2
除了插入Date具有DateTime值的列外,我们遇到了同样的问题
adam0101 '16

1
同样在这里。我们有一个数据仓库记录,并且使用时间戳作为密钥的一部分。数据仓库中的时间戳是SQL DateTime,但是C#中的时间戳不匹配。我将SQL数据类型更改为DateTime2(7),更新了EF模型,并且所有问题均已解决。
mmcfly

将列更改为Datetime2(7)也对我有用。感谢@mmcfly
Dzejms

10

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

我的模型使用的Bind(Exclude)是实体ID上的属性,这导致HttpPost上的实体ID的值为零。

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; }
    }
}   

类似的问题,出于安全原因,我有Bind(include =一些字段)。ID不在列表中。我也将其添加为隐藏输入。必须擦除了MVC生成的内容,或者ID根本不存在。谢谢您的帮助。
MusicAndCode

10

我有同样的问题,我发现这是由RowVersion引起的,该结果为null。检查您的IDRowVersion是否不为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


在我的情况下,行版本为空
Prakash 2015年

就我而言,我不小心删除了[Bind(Include = properties)]中的ID字段。重新添加,效果很好。
卡弗曼

8

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

为了在一个地方了解它可能发生的条件,我在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)在适用的地方调用。


1
好的,其他所有人都在抱怨这个问题,展示了如何触发它,等等,但是这个答案很酷。我使用一个持续更新模型(宝贝,这里没有保存按钮),并且当EF线程落后时,正在网格更新中获取此模型,并解决了这个问题。辉煌的工作我的好名字..你让我看起来像个英雄-站在巨人的肩膀上!
Tony Trembath-Drake

帮我过,看这更多的选项- stackoverflow.com/a/13891724/4836581
兹维Redler

7

您需要显式包括主键的BoundField。如果您不希望用户看到主键,则必须通过CSS隐藏它:

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

其中“隐藏”是css中的类,其显示设置为“无”。


1
呵呵,您误导了我删除ASP.NET MVC中隐藏的id字段的事实。谢谢@Paulo!:)
Tomasz Iniewicz 2012年

7

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

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

解决了这个问题。

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


7

我也遇到了这个错误。原来的问题是由我要保存到的表上的触发器引起的。触发器使用了“ INSTEAD OF INSERT”,这意味着曾经向该表插入0行,因此会出现错误。幸运的是,在某些情况下,触发功能不正确,但是我想这可能是有效的操作,应该以某种方式在代码中进行处理。希望有一天有帮助。


2
可以诱使实体相信通过从触发器返回SELECT语句(带有主键列)来添加行。
贾胡

1
为了扩展@jahu的注释,我必须从触发器中获取要返回的新插入项的实际ID,并且列名必须与触发器表的Identity列匹配(在我的情况下,实际上是一个视图,因此它没有自己的身份,但我欺骗edmx相信它确实如此。我的触发器正在向一个单独的表中插入,所以我在触发器中添加了最后一行:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister


在我的情况下,我正在对子集合中的实体执行删除操作,但是对于其中一个子实体的删除操作触发了一个触发器,从而导致另一个子实体被删除。这引起了错误,因为在实体框架尝试删除子实体之一之前,触发器删除了子实体本身之一,从而影响了N-1行。
skeletank

6

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


5

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

去做这个:

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

这将确保实体使用或添加与您合作的州来了解您。此时,需要设置所有正确的模型值。小心不要丢失任何可能在后台进行的更改。

希望这可以帮助。


1
你是一个古鲁!它对我有用!
Hernaldo Gonzalez

5
  @Html.HiddenFor(model => model.RowVersion)

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


没有将RowVersion从View传递到edit Action,而且我忘了为RowVersion进行模型绑定。在将对象保存到db时,需要将RowVersion的先前值与对象一起提交给db,以进行并发检查。当您需要更快的东西时,您会犯一些愚蠢的错误!
Dhanuka777 '16

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; }

4

只要确保表和表单都更新了主键和edmx。

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


4

我有同样的问题。就我而言,我试图更新主键,这是不允许的。


4

我在使用 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();
}

尽管这解决了我的问题,但它有助于指出本文前面提到的有关PK和行版本的潜在问题。我忽略了为新表添加架构映射,但由于PK不遵循命名约定规则,这一事实使情况更加复杂。<表名称> ID。
midohioboarder

3

当我删除数据库中的某些行(在循环中)并在同一表中添加新行时,出现了该错误。

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


我不得不做同样的事情,仍然不确定为什么问题会首先出现,但这是可行的。
杰德·格兰特2014年

3
    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();
                }
        }
    }

您能说明一下这里的“ this”是什么以及ObjectStateManager是什么吗?我正在我们的基本存储库类中尝试此操作,但是遇到了错误
Naomi

3

如果您尝试插入一个唯一的约束情况,也将发生这种情况,即,如果每个雇主只能拥有一种地址,并且尝试向同一雇主插入另一种相同类型的地址,则会遇到相同的问题。

要么

如果为所有分配给它们的对象属性分配了与以前相同的值,则也会发生这种情况。

        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
        }

2

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


2

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

context.Users.Attach(orderer);

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

2

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


2

在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的错,而是错误的null合并“ ??” 在将废话发送到数据层的View Controller中向上声明。


2

上面的答案都没有完全涵盖我的情况及其解决方案。

在MVC5控制器中引发错误的代码:

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

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

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


2

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

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


2

由于datetime和datetime2之间不匹配,这发生在我身上。奇怪的是,在测试人员发现问题之前,它运行良好。我的代码优先模型包括DateTime作为主键的一部分:

[Key, Column(Order = 2)]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

生成的列是日期时间列。调用SaveChanges时,EF生成了以下SQL:

-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))

因为它试图将datetime列与datetime2值匹配,所以没有返回结果。我能想到的唯一解决方案是将列更改为datetime2:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

1
它的工作与不工作的陌生感与的基本格式/基地做datetime对比datetime2。本质上,某些毫秒值将计算为匹配值,而其他则不会。我发生了同样的事情,我也转向了DateTime2
xr280xr

+1希望我可以为您+100。在许多地方仔细研究之后,我终于发现了这一点,并意识到,实际上,我有一个Datetime作为主键的一部分。是的,这确实解决了它。我将该列更新为Datetime2并成功了。现在,我的强项是使用Entity Framework来为此设计一个糟糕的查询,这迫使我去做。
Catchops,
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.