我有一个使用实体框架的项目。而在我的DbContext上调用SaveChanges时,我得到了以下异常:

System.Data.Entity.Validation.DbEntityValidationException:验证 一个或多个实体失败。参见'EntityValidationErrors'属性 欲知详情。

这一切都很好,但我不希望每次发生此异常时都附加调试器。此外,在生产环境中,我不能轻易地附加调试器,因此我必须竭尽全力重现这些错误。

我如何才能看到隐藏在DbEntityValidationException中的细节?


当前回答

最简单的解决方案是覆盖实体类上的SaveChanges。您可以捕获DbEntityValidationException,打开实际错误并使用改进的消息创建一个新的DbEntityValidationException。

在SomethingSomething.Context.cs文件旁边创建一个partial类。 使用这篇文章底部的代码。 就是这样。您的实现将自动使用覆盖的SaveChanges,而不需要任何重构工作。

你的异常消息现在看起来像这样:

System.Data.Entity.Validation.DbEntityValidationException:验证 一个或多个实体失败。参见'EntityValidationErrors'属性 欲知详情。验证错误如下 必须是字符串或数组类型,最大长度为'12';的 LastName字段是必需的。

你可以在任何继承自DbContext的类中删除被重写的SaveChanges:

public partial class SomethingSomethingEntities
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            // Retrieve the error messages as a list of strings.
            var errorMessages = ex.EntityValidationErrors
                    .SelectMany(x => x.ValidationErrors)
                    .Select(x => x.ErrorMessage);
    
            // Join the list to a single string.
            var fullErrorMessage = string.Join("; ", errorMessages);
    
            // Combine the original exception message with the new one.
            var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
    
            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

DbEntityValidationException还包含导致验证错误的实体。因此,如果您需要更多的信息,您可以更改上面的代码以输出关于这些实体的信息。

参见:http://devillers.nl/improving-dbentityvalidationexception/

其他回答

在调试过程中通过检查错误来快速找到有意义的错误消息:

添加一个快速手表: ((System.Data.Entity.Validation.DbEntityValidationException)例外)美元.EntityValidationErrors 向下钻取EntityValidationErrors,如下所示: > ValidationErrors >(收集项,如[0])> ErrorMessage

最简单的解决方案是覆盖实体类上的SaveChanges。您可以捕获DbEntityValidationException,打开实际错误并使用改进的消息创建一个新的DbEntityValidationException。

在SomethingSomething.Context.cs文件旁边创建一个partial类。 使用这篇文章底部的代码。 就是这样。您的实现将自动使用覆盖的SaveChanges,而不需要任何重构工作。

你的异常消息现在看起来像这样:

System.Data.Entity.Validation.DbEntityValidationException:验证 一个或多个实体失败。参见'EntityValidationErrors'属性 欲知详情。验证错误如下 必须是字符串或数组类型,最大长度为'12';的 LastName字段是必需的。

你可以在任何继承自DbContext的类中删除被重写的SaveChanges:

public partial class SomethingSomethingEntities
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            // Retrieve the error messages as a list of strings.
            var errorMessages = ex.EntityValidationErrors
                    .SelectMany(x => x.ValidationErrors)
                    .Select(x => x.ErrorMessage);
    
            // Join the list to a single string.
            var fullErrorMessage = string.Join("; ", errorMessages);
    
            // Combine the original exception message with the new one.
            var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
    
            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

DbEntityValidationException还包含导致验证错误的实体。因此,如果您需要更多的信息,您可以更改上面的代码以输出关于这些实体的信息。

参见:http://devillers.nl/improving-dbentityvalidationexception/

正如Martin所指出的,在DbEntityValidationResult中有更多信息。我发现在每条消息中同时获取POCO类名和属性名很有用,并且希望避免为此在所有[Required]标记上编写自定义ErrorMessage属性。

以下对Martin代码的调整为我解决了这些细节问题:

// Retrieve the error messages as a list of strings.
List<string> errorMessages = new List<string>();
foreach (DbEntityValidationResult validationResult in ex.EntityValidationErrors)
{
    string entityName = validationResult.Entry.Entity.GetType().Name;
    foreach (DbValidationError error in validationResult.ValidationErrors)
    {
        errorMessages.Add(entityName + "." + error.PropertyName + ": " + error.ErrorMessage);
    }
}

我认为“实际的验证错误”可能包含敏感信息,这可能是微软选择将它们放在另一个地方(属性)的原因。这里标出的解决办法是可行的,但应谨慎使用。

我更喜欢创建一个扩展方法。还有更多的原因:

保留原始堆栈跟踪 遵循开放/封闭原则。:我可以对不同类型的日志使用不同的消息) 在生产环境中,可能存在其他位置(例如。: other dbcontext),其中DbEntityValidationException可能被抛出。

当您在catch{…打开“QuickWatch”窗口(ctrl+alt+q)并粘贴在那里:

((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors

这将允许您深入到ValidationErrors树。这是我发现的最简单的方法来立即洞察这些错误。

对于Visual 2012+用户,他们只关心第一个错误,可能没有catch块,你甚至可以这样做:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage