entity framework:“存储更新,插入或删除语句影响了意外数量的行(0)”。
我正在使用entity framework来填充网格控件。 有时当我进行更新时,出现以下错误:
存储更新,插入或删除语句影响了意外数量的行(0)。 实体被加载后,实体可能已被修改或删除。 刷新ObjectStateManager条目。
我无法弄清楚如何重现这一点。 但是这可能与我做出更新的距离有多大关系。 有没有人看到这个或没有人知道错误信息是指什么?
编辑:不幸的是,我不再可以重现我在这里所遇到的问题,因为我离开了这个项目,不记得我是否最终find了解决scheme,是否有其他开发者修复了这个问题,或者我是否解决了这个问题。 所以我不能接受任何答案。
这是乐观并发function的一个副作用。
不是100%确定如何在Entity Framework中打开/closures它,但基本上它告诉你,当你从数据库中抓取数据,当你保存你的更改时,别人已经改变了数据(这意味着当你去保存0行实际上得到更新)。 在SQL方面,它们的update
查询的where
子句包含行中每个字段的原始值,如果0行受到影响,它知道出了什么问题。
它背后的想法是,你不会最终覆盖你的应用程序不知道发生的变化 – 这基本上是所有的更新.NET的一个小安全措施。
如果它是一致的,那么它就发生在你自己的逻辑中(EG:你实际上是用select和更新之间的另一种方法来更新数据),但它可能只是两个应用程序之间的竞争条件。
我遇到了这个问题,这是由于没有设置实体的ID(密钥)字段造成的。 因此,当上下文去保存数据,它不能find一个ID = 0。一定要在您的更新语句中放置一个断点,并validation实体的ID已被设置。
来自Paul Bellora的评论
我有这个确切的问题,由忘记在.cshtml编辑页面中包含隐藏的IDinput引起的
哇,很多答案,但是当我做了一些稍微不同的事情时,我得到了这个错误,没有其他人提到。
长话短说,如果你创build一个新的对象,并告诉EF使用EntityState.Modified
修改它,那么它将抛出这个错误,因为它还不存在于数据库中。 这是我的代码:
MyObject foo = new MyObject() { someAttribute = someValue }; context.Entry(foo).State = EntityState.Modified; context.SaveChanges();
是的,这似乎是愚蠢的,但它起因于有问题的方法曾经有foo
传递给它,现在它只有一些值传递给它,并创buildfoo
本身。
轻松修复,只需将EntityState.Modified
更改为EntityState.Added
或将整行更改为:
context.MyObject.Add(foo);
我正面临着同样的惊吓错误… :)然后,我意识到,我忘了设置一个
@Html.HiddenFor(model => model.UserProfile.UserId)
为正在更新的对象的主键! 我倾向于忘记这个简单,但非常重要的事情!
顺便说一下: HiddenFor
是ASP.NET MVC。
检查您是否忘记了GridView中的“DataKeyNames”属性。 在GridView中修改数据是必须的
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx
这个问题是由以下两件事之一引起的:
- 您尝试更新具有一个或多个属性的行是
Concurrency Mode: Fixed
,并且乐观并发防止数据被保存。 IE浏览器。 有些人在收到服务器数据和保存服务器数据之间更改了行数据。 - 您尝试更新或删除一行,但该行不存在。 另一个例子有人更改数据(在这种情况下,删除)之间的检索然后保存或你平我们试图更新一个字段是不是一个身份(即
StoreGeneratedPattern = Computed
),并且该行不存在。
我有同样的问题,@ Webtrifusion的答案帮助find解决scheme。
我的模型在实体的ID上使用了Bind(Exclude)
属性,导致实体的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; } } }
我有同样的问题,我找出是由RowVersion是空的。 检查你的Id和你的RowVersion是不是null 。
有关更多信息,请参阅本教程
在编辑时,将实体的ID或主键作为隐藏字段添加到视图中
即
@Html.HiddenFor(m => m.Id)
解决了这个问题。
此外,如果您的模型包括不使用的项目也包括那并且发布到控制器
您需要显式包含主键的BoundField。 如果您不希望用户看到主键,则必须通过css隐藏它:
<asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" HeaderStyle-CssClass="hidden" />
“隐藏”是CSS中的一个类,它的显示设置为“无”。
我也遇到了这个错误。 问题原来是由我试图保存的表上的触发器引起的。 触发器使用“INSTEAD OF INSERT”,意味着有0行被插入到表中,因此错误。 幸运的是,在这种情况下,触发器function是不正确的,但我想这可能是一个有效的操作,应该以代码方式处理。 希望这有助于某一天。
只要确保表和表都有主键和edmx更新。
我发现更新过程中的任何错误通常是因为: – 表中没有主键 – 编辑视图/表单中没有主键(例如@Html.HiddenFor(m=>m.Id
)
@Html.HiddenFor(model => model.RowVersion)
我排队是空的,所以不得不添加到解决我的问题的看法
我得到了同样的错误,因为部分PK是一个date时间列,插入的logging使用DateTime.Now作为该列的值。 entity framework将以毫秒级精度插入该值,然后以毫秒级精度查找刚刚插入的值。 但是,SqlServer已经将值舍入为第二精度,因此entity framework无法find毫秒精度值。
解决方法是在插入之前从DateTime.Now中截断毫秒。
当我删除数据库中的一些行(在循环中),并在同一个表中添加新行时,我得到了这个错误。
对我来说,解决scheme是dynamic地在每个循环迭代中创build一个新的上下文
我有同样的问题。 在我的情况下,我试图更新主键,这是不允许的。
如果您尝试在您的edmx文件中创build映射到“函数导入”,则可能导致此错误。 只需清除位于您的edmx中给定实体的映射详细信息中的插入,更新和删除字段,它应该可以工作。 我希望我说清楚。
如果您试图插入一个唯一的约束条件,也就是说,如果您只能为每个雇主提供一种types的地址,并且您尝试向同一个雇主插入相同types的另一个types,那么也会发生同样的问题。
要么
如果分配给的所有对象属性都会发生这种情况,那么它们将被赋予与以前相同的值。
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 }
那么我有这个相同的问题。 但这是由于我自己的错误。 其实我是保存一个对象,而不是添加它。 所以这是冲突。
在Sql Server环境中debugging此问题的一种方法是使用您的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中的查询窗口并执行它。 果然,虽然它运行,0logging受到这个查询影响,因此EF返回错误。
在我的情况下,问题是由CategoryID造成的。
没有由ID EF发送给数据库的CategoryID,因此影响了0条logging。
这不是EF的过错,而是一个错误的空合并“??” 声明在一个视图控制器发送废话到数据层。
从model-first改为code-first之后,我开始出现这个错误。 我有多个线程更新数据库,其中一些可能会更新同一行。 我不知道为什么我没有使用model-first的问题,假设它使用不同的并发默认值。
为了处理它在一个地方知道它可能发生的条件,我添加了以下重载到我的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)
。
我遇到了这个使用Telerik的RadGrid。 我把主键设置为只读的网格列。 如果列是显示=“假”,但只读=“真”造成的问题,它会工作正常。 我通过使gridbound列显示= 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>
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(); } } }
刚刚有同样的问题。
我正在使用EF 6,Code First + Migrations。 问题是我们的DBA在抛出错误的表上创build了一个约束。
上述答案都不能很好地说明我的情况和解决办法。
在MVC5控制器中抛出错误的代码:
if (ModelState.IsValid) { db.Entry(object).State = EntityState.Modified; db.SaveChanges(); // line that threw exception return RedirectToAction("Index"); }
当我从“编辑”视图保存对象时收到此exception。 扔它的原因是因为当我回去保存它时,我修改了在对象上形成主键的属性。 因此,将其状态设置为“修改”对于EF来说没有任何意义 – 这是一个新条目,而不是以前保存的条目。
你可以通过A)修改保存调用来添加对象,或者B)只是在编辑时不要改变主键。 我做了B)。
当被接受的答案是“ 最终不会覆盖你的申请不知道发生的变化 ”时,我怀疑是因为我的对象是新创build的。 但是,事实certificate,有一个INSTEAD OF UPDATE, INSERT- TRIGGER
附加在正在更新同一个表的计算列的表上。
一旦我改变这个AFTER INSERT, UPDATE
,它工作正常。
在我们的例子中,这个错误是由于标记实体被修改的时候,当它们的属性没有真的被改变时。 例如,当您将相同的值分配给属性时,上下文可能会将其视为数据库不存在的更新。
基本上我们运行了一个脚本来重新填充其他属性的连接值的一个属性。 对于许多logging,这意味着没有改变,但它被标记为修改。 DB返回了不同数量的更新对象,这大概会触发该exception。
我们通过检查属性值来解决这个问题,如果不同,只分配一个新属性。
在同一个上下文中使用SaveChanges(false)和SaveChanges()时出现这个错误,在从两个表中删除多行的单元工作中(在上下文中)(SaveChanges(False)在其中一个删除中)在调用函数SaveChanges()被调用….解决scheme是删除不必要的SaveChanges(false)。
为了防止有人在并行循环中运行时遇到这个问题,我将把它抛出:
Parallel.ForEach(query, deet => { MyContext ctx = new MyContext(); //do some stuff with this to identify something if(something) { //Do stuff ctx.MyObjects.Add(myObject); ctx.SaveChanges() //this is where my error was being thrown } else { //same stuff, just an update rather than add } }
我将其更改为以下内容:
Parallel.ForEach(query, deet => { MyContext ctxCheck = new MyContext(); //do some stuff with this to identify something if(something) { MyContext ctxAdd = new MyContext(); //Do stuff ctxAdd .MyObjects.Add(myObject); ctxAdd .SaveChanges() //this is where my error was being thrown } else { MyContext ctxUpdate = new MyContext(); //same stuff, just an update rather than add ctxUpdate.SaveChanges(); } }
不知道这是否是“最佳实践”,但它通过让每个并行操作使用自己的上下文来解决我的问题。
我今天有一个类似的问题,我将在这里logging它,因为它不是乐观的并发错误。
我正在将一个旧的系统转换为一个新的数据库,并有几千个实体,我不得不将这些实体编写到新的系统中。 但是,为了帮助理智,我select保留原始的唯一ID,然后将其注入到新对象中,然后尝试保存它。
我遇到的问题是我使用MVC Scaffolding来创build基础知识库,他们在UpdateOrInsert方法中有一个模式,基本上检查是否在添加新的实体或将其状态更改为已修改之前设置了Key属性。
由于Guid已设置,它试图修改数据库中实际不存在的行。
我希望这可以帮助别人!