查找DBUpdateException的原因
本文关键字:DBUpdateException 查找 | 更新日期: 2023-09-27 17:50:54
当调用DbContext.SaveChanges
时,我得到一个DbUpdateException:
类型的未处理异常"System.Data.Entity.Infrastructure。DbUpdateException'发生在EntityFramework.dll。附加信息:发生错误更新条目。详情请参阅内部异常。不幸的是,没有内部异常(至少在我看来没有)。有什么方法可以看到
SaveChanges
抛出异常的确切原因吗?至少,了解发生错误时SaveChanges试图使用哪个表进行更新是有帮助的。
这是我对SaveChanges的重写。它为我提供了一个放置断点的有用位置:
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Debug.WriteLine(@"Entity of type ""{0}"" in state ""{1}""
has the following validation errors:",
eve.Entry.Entity.GetType().Name,
eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
Debug.WriteLine(@"- Property: ""{0}"", Error: ""{1}""",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
catch(DbUpdateException e)
{
//Add your code to inspect the inner exception and/or
//e.Entries here.
//Or just use the debugger.
//Added this catch (after the comments below) to make it more obvious
//how this code might help this specific problem
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
throw;
}
}
参考:一个或多个实体的验证失败。看到& # 39;EntityValidationErrors& # 39;
这是我对SaveChanges的重写,显示了处理DbUpdateException(根据问题)的额外代码。
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException vex)
{
var exception = HandleDbEntityValidationException(vex);
throw exception;
}
catch(DbUpdateException dbu)
{
var exception = HandleDbUpdateException(dbu);
throw exception;
}
}
private Exception HandleDbUpdateException(DbUpdateException dbu)
{
var builder = new StringBuilder("A DbUpdateException was caught while saving changes. ");
try
{
foreach (var result in dbu.Entries)
{
builder.AppendFormat("Type: {0} was part of the problem. ", result.Entity.GetType().Name);
}
}
catch (Exception e)
{
builder.Append("Error parsing DbUpdateException: " + e.ToString());
}
string message = builder.ToString();
return new Exception(message, dbu);
}
我没有使日志代码非常具体,但它改进了标准的错误消息,如:
The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.
这样,至少我可以看到哪个实体有问题,这通常足以解决问题。
根据Colin的回答,可以提供EF持久性失败的完整详细信息,如下所示:
public bool SaveChangesEx()
{
try
{
SaveChanges();
return true;
}
catch (DbEntityValidationException exc)
{
// just to ease debugging
foreach (var error in exc.EntityValidationErrors)
{
foreach (var errorMsg in error.ValidationErrors)
{
// logging service based on NLog
Logger.Log(LogLevel.Error, $"Error trying to save EF changes - {errorMsg.ErrorMessage}");
}
}
throw;
}
catch (DbUpdateException e)
{
var sb = new StringBuilder();
sb.AppendLine($"DbUpdateException error details - {e?.InnerException?.InnerException?.Message}");
foreach (var eve in e.Entries)
{
sb.AppendLine($"Entity of type {eve.Entity.GetType().Name} in state {eve.State} could not be updated");
}
Logger.Log(LogLevel.Error, e, sb.ToString());
throw;
}
}
除了验证错误之外,update exception还将输出一般错误和上下文信息。
注意:需要c# 6.0才能工作,因为它使用null传播和字符串插值。
对于。net Core,代码略有变化,因为可能引发的异常具有不同的结构/填充方式不同:
public void SaveChangesEx()
{
try
{
// this triggers defined validations such as required
Context.Validate();
// actual save of changes
Context.SaveChangesInner();
}
catch (ValidationException exc)
{
Logger.LogError(exc, $"{nameof(SaveChanges)} validation exception: {exc?.Message}");
throw;
}
catch (DbUpdateException exc)
{
Logger.LogError(exc, $"{nameof(SaveChanges)} db update error: {exc?.InnerException?.Message}");
throw;
}
catch (Exception exc)
{
// should never reach here. If it does, handle the more specific exception
Logger.LogError(exc, $"{nameof(SaveChanges)} generic error: {exc.Message}");
throw;
}
}
Context可以增强为在失败时自动拒绝更改,如果相同的上下文没有立即被处理:
public void RejectChanges()
{
foreach (var entry in ChangeTracker.Entries().Where(e => e.Entity != null).ToList())
{
switch (entry.State)
{
case EntityState.Modified:
case EntityState.Deleted:
entry.State = EntityState.Modified; //Revert changes made to deleted entity.
entry.State = EntityState.Unchanged;
break;
case EntityState.Added:
entry.State = EntityState.Detached;
break;
}
}
}
public bool SaveChangesInner()
{
try
{
SaveChanges();
return true;
}
catch (Exception)
{
RejectChanges();
throw;
}
}
当真正的异常似乎丢失在某个地方时,最好的办法是在每个异常上都中断。无论它是否被捕获或吞噬在某个地方,在您的范围内或之外,调试器都会断开并允许您查看发生了什么。
有关更多信息,请参阅此MSDN链接:
如何:打破当一个异常被抛出
我有同样的错误"转换datetime2数据类型到datetime数据类型导致一个超出范围的值。'r'n语句已终止。"
我把日期时间值字段像这样日期时间。现在
var person = new Person
{
FirstName = "Sebastian",
LastName = "Back",
**BirthDate = DateTime.Now,**
IsActive = true,
};
我也面临同样的问题
如果你正在使用SQL Server,你有父表和子表与(FK)外键,
确保表之间的关系,例如在Delete或Update时CASCADE。
我得到了同样的错误,并像那样解决;
我有一个数据类型是datetime的字段,我知道我正在设置它而没有分配datetime属性。所以我把它改成"Datetime"。现在"然后我看到问题解决了,它已成功保存
在我的情况下,我使用存储过程添加一个实体到DB。我的SP给出了运行时错误,因为我在c#中得到了这个错误。我纠正了SP, EF工作得很好。因此,如果您正在使用SP在EF中添加,编辑,删除或更新,请检查相应的SP是否正常工作。
在我的情况下,我有创建表作为DOMAIN'MyUser.TableName
没有注意到…相反,我需要将其重新创建为dbo.TableName
。
{"ClassName"System.Data.Entity.Infrastructure.DbUpdateException","Message":"一个更新条目时发生错误。参见内部异常细节!","Data" null,"InnerException":{"ClassName"System.Data.Entity.Core.UpdateException","Message":"一个更新条目时发生错误。参见内部异常细节!","Data" null,"InnerException":{"Errors"[{"Source"。netSqlClient数据Provider"Number": 208年,"State": 1,"Class": 16日,"Server":"* * *","Message":"无效的对象名称dbo.TableName !","Procedure"","LineNumber" 1}],"ClientConnectionId":"ab3fcb89 - 392 d - 42 - a5 - 9548 - 19 - a8d0cf0cdb"ClassName":"System.Data.SqlClient.SqlException"Message":"无效的对象名称dbo.TableName !","Data"{"HelpLink.ProdName"微软SQLServer"HelpLink.ProdVer":"15.00.2000"HelpLink.EvtSrc":"MSSQLServer"HelpLink.EvtID":"208","HelpLink.BaseHelpUrl":"http://go.microsoft.com/fwlink","HelpLink.LinkId":"20476"}
在我的情况下是一个c# datetime字段值'1/1/0001 12:00:00 AM +00:00'当SQL只接受'1/1/1753 12:00:00 AM'之后的值。解决方案:
返回新的DateTime(Math.Max(date. time))。
在我的例子中,是数据库表和实体模型之间的列名不匹配!