查找DBUpdateException的原因

本文关键字:DBUpdateException 查找 | 更新日期: 2023-09-27 17:50:54

当调用DbContext.SaveChanges时,我得到一个DbUpdateException:

类型的未处理异常"System.Data.Entity.Infrastructure。DbUpdateException'发生在EntityFramework.dll。附加信息:发生错误更新条目。详情请参阅内部异常。
不幸的是,没有内部异常(至少在我看来没有)。有什么方法可以看到SaveChanges抛出异常的确切原因吗?至少,了解发生错误时SaveChanges试图使用哪个表进行更新是有帮助的。

查找DBUpdateException的原因

这是我对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))。

在我的例子中,是数据库表和实体模型之间的列名不匹配!

相关文章:
  • 没有找到相关文章