我正在使用Entity Framework来填充网格控件。有时当我进行更新时,我收到以下错误:
存储更新,插入或删除语句会影响意外的行数(0)。自实体加载后,实体可能已被修改或删除。刷新ObjectStateManager条目。
我无法弄清楚如何重现这一点。但它可能与我进行更新的距离有多大关系。有没有人看过这个或有没有人知道错误信息是指什么?
编辑:不幸的是我不再能够重现我在这里遇到的问题,因为我离开了这个项目并且不记得我是否最终找到了解决方案,如果其他开发人员修复了它,或者我是否工作过周围。因此,我不能接受任何答案。
答案 0 :(得分:375)
我遇到了这个问题,这是由于实体的ID(密钥)字段没有设置造成的。因此,当上下文保存数据时,它找不到ID = 0.请确保在更新语句中放置一个断点并验证是否已设置实体的ID。
来自Paul Bellora的评论
由于忘记包含隐藏的ID,我遇到了这个问题 输入.cshtml编辑页面
答案 1 :(得分:184)
这是一种称为乐观并发的功能的副作用。
不是100%确定如何在实体框架中打开/关闭它,但基本上它告诉你的是,当你从数据库中抓取数据和保存更改时,其他人已经更改了数据(这意味着当你去保存它时,0行实际上已更新)。在SQL术语中,他们的update
查询的where
子句包含行中每个字段的原始值,如果0行受到影响,它就会知道出错了。
它背后的想法是你不会最终覆盖你的应用程序不知道发生的变化 - 这基本上是.NET在你所有更新中引入的一点安全措施。
如果它是一致的,可能在你自己的逻辑中发生(EG:你实际上是在选择和更新之间的另一种方法中自己更新数据),但它可能只是两个应用程序之间的竞争条件
答案 2 :(得分:102)
简而言之,如果您创建一个新对象并告诉EF使用EntityState.Modified
修改它,那么它将抛出此错误,因为它在数据库中尚不存在。这是我的代码:
MyObject foo = new MyObject()
{
someAttribute = someValue
};
context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();
是的,这看起来很愚蠢,但它之所以产生,是因为前面已经创建了传递给它的foo
的问题,现在它只传递了someValue
并创建了{{ 1}}本身。
轻松修复,只需将foo
更改为EntityState.Modified
或将整行更改为:
EntityState.Added
答案 3 :(得分:22)
我面对同样的惊吓错误...... :)然后我意识到我忘了设置
@Html.HiddenFor(model => model.UserProfile.UserId)
用于更新对象的主键!我倾向于忘记这个简单但非常重要的东西!
顺便说一下:HiddenFor
适用于ASP.NET MVC。
答案 4 :(得分:16)
检查您是否忘记了GridView中的“DataKeyNames”属性。 在GridView中修改数据时必须使用它
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx
答案 5 :(得分:15)
问题是由以下两种情况之一引起的: -
Concurrency Mode: Fixed
的行...而且Optimistic Concurrency阻止了数据的保存。 IE浏览器。有些人在收到服务器数据和保存服务器数据之间更改了行数据。 StoreGeneratedPattern = Computed
)而该行没有存在。答案 6 :(得分:11)
我得到了同样的错误,因为PK的一部分是一个日期时间列,而插入的记录使用DateTime.Now作为该列的值。实体框架将以毫秒精度插入值,然后以毫秒精度查找刚刚插入的值。但是,SqlServer将该值四舍五入为第二精度,因此实体框架无法找到毫秒精度值。
解决方案是在插入之前截断DateTime.Now的毫秒数。
答案 7 :(得分:9)
我有同样的问题,我发现这是由RowVersion引起的,它是null。 检查您的 ID 和 RowVersion 不为空。
有关更多信息,请参阅本教程
答案 8 :(得分:9)
我遇到了同样的问题,@ webtrifusion的answer帮助找到了解决方案。
我的模型在实体的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; }
}
}
答案 9 :(得分:7)
我也遇到过这个错误。它的问题是由我试图保存到的表上的触发器引起的。触发器使用'INSTEAD OF INSERT',这意味着有0行插入到该表中,因此出错。幸运的是,触发器功能可能不正确,但我想这可能是一个有效的操作,应该以某种方式在代码中处理。希望有一天能帮到某人。
答案 10 :(得分:7)
编辑时将实体的id或主键包含在视图中的隐藏字段
即
@Html.HiddenFor(m => m.Id)
解决了这个问题。
此外,如果您的模型包含未使用的项目,也包含该项目并将其发布到控制器
答案 11 :(得分:6)
您需要明确包含主键的BoundField。如果您不希望用户看到主键,则必须通过css隐藏它:
<asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden"
HeaderStyle-CssClass="hidden" />
'hidden'是css中的一个类,它的显示设置为'none'。
答案 12 :(得分:5)
@Html.HiddenFor(model => model.RowVersion)
我的rowversion为null,因此必须将其添加到视图中 这解决了我的问题
答案 13 :(得分: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)
。
答案 14 :(得分: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; }
答案 15 :(得分:4)
我遇到了同样的问题。 在我的情况下,我试图更新主键,这是不允许的。
答案 16 :(得分: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();
}
答案 17 :(得分:4)
只需确保表和表单都有主键和edmx更新。
我发现更新期间的任何错误通常是因为:
- 表中没有主键
- 编辑视图/表单中没有主键(例如@Html.HiddenFor(m=>m.Id
)
答案 18 :(得分:3)
我在一个缺少主键并且有DATETIME(2,3)列的表上遇到了这个问题(因此实体的“主键”是所有列的组合)...执行插入时时间戳有一个更精确的时间(2018-03-20 08:29:51.8319154)被截断为(2018-03-20 08:29:51.832),因此关键字段的查找失败。
答案 19 :(得分:3)
我也有这个错误。在某些情况下,实体可能不知道您正在使用的实际数据库上下文或模型可能不同。为此,set:EntityState.Modified;到EntityState.Added;
要做到这一点:
if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}
这将确保实体知道您正在使用或添加您正在使用的州。此时需要设置所有正确的模型值。小心不要丢失可能在后台进行的任何更改。
希望这有帮助。
答案 20 :(得分:3)
当我删除数据库中的某些行(在循环中),并在同一个表中添加新行时,我收到了该错误。
对我来说,解决方案是动态地在每个循环迭代中创建一个新的上下文
答案 21 :(得分: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();
}
}
}
答案 22 :(得分:2)
如果您尝试在edmx文件中创建映射到“函数Imports”,则可能导致此错误。只需清除edmx中给定实体的映射详细信息中的插入,更新和删除字段,它就可以正常工作。 我希望我说清楚。
答案 23 :(得分:2)
由于datetime和datetime2之间不匹配,这发生在我身上。奇怪的是,在测试人员发现问题之前,它工作得很好。我的Code First模型包含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;
答案 24 :(得分:2)
当接受的答案说&#34; 它最终会覆盖您的应用程序不知道已经发生的变更&#34;时,我持怀疑态度,因为我的对象是新创建的。但事实证明,该表附加了一个 INSTEAD OF UPDATE, INSERT- TRIGGER
,它正在更新同一个表的计算列。
我将其更改为 AFTER INSERT, UPDATE
后,工作正常。
答案 25 :(得分:2)
上述答案都没有完全涵盖我的情况和解决方案。
MVC5控制器中抛出错误的代码:
if (ModelState.IsValid)
{
db.Entry(object).State = EntityState.Modified;
db.SaveChanges(); // line that threw exception
return RedirectToAction("Index");
}
我在编辑视图中保存对象时收到此异常。它抛出它的原因是因为当我回去保存它时,我修改了在对象上形成主键的属性。因此,将其状态设置为已修改对于EF没有任何意义 - 它是一个新条目,而不是之前保存的条目。
您可以通过以下方式解决此问题:A)修改保存调用以添加对象,或者B)不要在编辑时更改主键。我做了B)。
答案 26 :(得分:2)
我有同样的问题。但这是由于我自己的错误。实际上我正在保存一个对象而不是添加它。所以这就是冲突。
答案 27 :(得分:2)
在Sql Server环境中调试此问题的一种方法是使用SqlServer副本附带的Sql Profiler,或者如果使用Express版本,请通过以下链接从CodePlex免费获取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中声明向无意义发送到数据层。
答案 28 :(得分:2)
如果你试图插入一个独特的约束情况,也就是说如果你每个雇主只能有一种类型的地址,并且你试图在同一个雇主中插入同一类型的第二种类型,你也会得到同样的问题。
或强>
如果分配给所有对象属性,也可能会发生这种情况,它们被分配了与之前相同的值。
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
}
答案 29 :(得分:1)
当我意外地尝试更新对象而不是保存时,我遇到了这个问题!
我有
if (IsNewSchema(model))
unitOfWork.SchemaRepository.Update(schema);
else
unitOfWork.SchemaRepository.Insert(schema);
我什么时候应该
if (IsNewSchema(model))
unitOfWork.SchemaRepository.Insert(schema);
else
unitOfWork.SchemaRepository.Update(schema);
答案 30 :(得分:1)
遇到同样的问题。
我正在使用EF 6,Code First + Migrations。 问题是我们的DBA在抛出错误的表上创建了一个约束。
答案 31 :(得分:1)
我使用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>
答案 32 :(得分:1)
对于那些使用 AutoMapper 的人 如果要更新具有外键到另一个实体(或多个实体)的实体,请确保所有外部实体的主键都设置为生成数据库(或者为MySQL自动递增)。
例如:
public class BuyerEntity
{
[Key]
public int BuyerId{ get; set; }
public int Cash { get; set; }
public List<VehicleEntity> Vehicles { get; set; }
public List<PropertyEntity> Properties { get; set; }
}
车辆和物业存储在除买家之外的其他表格中。当您添加新买家时,AutoMapper和EF会自动更新“车辆”和“属性”表格,这样如果您没有在这些表格中设置自动增量(就像我没有),那么您将会看到OP问题的错误。
答案 33 :(得分:1)
附加数据库中不存在的对象时出现此异常。我假设对象是从单独的上下文加载的,但如果是用户第一次访问该站点,则该对象是从头开始创建的。我们有自动递增的主键,所以我可以替换
context.Users.Attach(orderer);
与
if (orderer.Id > 0) {
context.Users.Attach(orderer);
}
答案 34 :(得分:1)
如果尝试使用数据库中不存在的Id更新记录,则可能会发生这种情况。
答案 35 :(得分:0)
我收到了此异常,我在id
中将database's table
列设置为自动增量,然后它正常工作
答案 36 :(得分:0)
在我们的例子中,这个错误是由于当没有任何属性“真正”改变时将实体标记为已修改。例如,当您为属性分配相同的值时,上下文可能会将其视为数据库不存在的更新。
基本上我们运行了一个脚本来重新填充一个属性,其中包含来自其他属性的连接值。对于许多意味着没有变化的记录,但它将它们标记为已修改。 DB返回了不同数量的更新对象,这些对象可能会触发该异常。
我们通过检查属性值来解决它,如果不同则只分配新的属性。
答案 37 :(得分:0)
这恰好发生在我身上。我正在运行Aurora(AWS MySQL)并尝试将记录添加到表中。模型中标记为[Key]的字段被映射到表格中的自动递增字段......或者我认为。它被设置为主键,但未设置为自动增量。因此将其设置为自动增加可以解决我的问题。
答案 38 :(得分:0)
在注册新用户而不是:
时,我遇到了Mvc身份的问题var result = await UserManager.CreateAsync(user);
我在做:
var result = await UserManager.UpdateAsync(user);
答案 39 :(得分:0)
我们忘记提及“enctype”发布“多部分”表单数据。我刚刚面对的另一个场景......
答案 40 :(得分:0)
从表(ParentTable)中删除项目时出现同样的问题,该项由另外两个表外键使用ON DELETE CASCADE规则(RefTable1,RefTable2)引用。出现此问题的原因是其中一个引用表(RefTable1)上的“AFTER DELETE”触发器。此触发器正在从ParentTable中删除相关记录,因为结果RefTable2记录也被删除。 似乎实体框架,而in-code被明确设置为删除ParentTable记录,是从RefTable1中删除相关记录,然后在后一次操作后从RefTable2记录引发此异常,因为触发器已从ParentTable中删除记录,结果删除了RefTable2记录。
答案 41 :(得分:0)
最近,我正在尝试将EF5升级到EF6示例项目。示例项目表具有十进制(5,2)类型列。数据库迁移成功完成。但是,初始数据种子生成异常。
型号:
public partial class Weather
{
...
public decimal TMax {get;set;}
public decimal TMin {get;set;}
...
}
配置错误:
public partial class WeatherMap : EntityTypeConfiguration<Weather>
{
public WeatherMap()
{
...
this.Property(t => t.TMax).HasColumnName("TMax");
this.Property(t => t.TMin).HasColumnName("TMin");
...
}
}
数据:
internal static Weather[] data = new Weather[365]
{
new Weather() {...,TMax = 3.30M,TMin = -12.00M,...},
new Weather() {...,TMax = 5.20M,TMin = -10.00M,...},
new Weather() {...,TMax = 3.20M,TMin = -8.00M,...},
new Weather() {...,TMax = 11.00M,TMin = -7.00M,...},
new Weather() {...,TMax = 9.00M,TMin = 0.00M,...},
};
我发现问题,种子数据有精度值,但配置没有精度和比例参数。 TMax和TMin字段在样本表中用十进制(10,0)定义。
正确配置:
public partial class WeatherMap : EntityTypeConfiguration<Weather>
{
public WeatherMap()
{
...
this.Property(t => t.TMax).HasPrecision(5,2).HasColumnName("TMax");
this.Property(t => t.TMin).HasPrecision(5,2).HasColumnName("TMin");
...
}
}
我的示例项目运行:MySql 5.6.14,Devart.Data.MySql,MVC4,.Net 4.5.1,EF6.01
最好的问候。
答案 42 :(得分:0)
在同一个上下文中使用SaveChanges(false)和稍后的SaveChanges()时出现此错误,在一个单元工作中,从两个表中删除多行(在上下文中)(SaveChanges(False)位于其中一个删除。然后在调用函数中调用SaveChanges()....解决方法是删除不必要的SaveChanges(false)。
答案 43 :(得分:0)
我会抛出这个以防万一有人在并行循环中遇到这个问题:
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();
}
}
不确定这是否是“最佳实践”,但它解决了我的问题,让每个并行操作都使用自己的上下文。
答案 44 :(得分:0)
我今天遇到了类似的问题,我会在这里记录,因为它并不是乐观的并发错误。
我正在将一个旧系统转换为一个新的数据库,它有几千个实体,我必须将其编写到新系统。但是,为了帮助理智,我选择保留原始的唯一ID,因此将其注入新对象,然后尝试保存它。
我遇到的问题是我使用MVC Scaffolding来创建基本存储库,并且他们在UpdateOrInsert方法中有一个模式,它基本上检查Key属性是否在它添加新实体或更改之前设置国家要修改。
因为设置了Guid,所以它试图修改数据库中实际不存在的行。
我希望这有助于其他人!