DbEntityValidationException – 如何轻松地告诉造成错误的原因?

我有一个使用entity framework的项目。 在我的DbContext上调用SaveChanges时,出现以下exception:

System.Data.Entity.Validation.DbEntityValidationException:一个或多个实体的validation失败。 有关更多详细信息,请参阅“EntityValidationErrors”属性。

这一切都很好,但我不希望每当发生这种exception时都附加一个debugging器。 更重要的是,在生产环境中,我不能轻易地附加一个debugging器,所以我必须竭尽全力去重现这些错误。

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

最简单的解决scheme是在您的实体类上重写SaveChanges 。 您可以捕获DbEntityValidationException ,解开实际的错误,并使用改进的消息创build新的DbEntityValidationException

  1. 在SomethingSomething.Context.cs文件旁边创build一个部分类。
  2. 使用这篇文章底部的代码。
  3. 而已。 您的实现将自动使用重写SaveChanges而不需要任何重构工作。

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

System.Data.Entity.Validation.DbEntityValidationException:一个或多个实体的validation失败。 有关更多详细信息,请参阅“EntityValidationErrors”属性。 validation错误是:PhoneNumber字段必须是最大长度为'12'的string或数组types。 LastName字段是必需的。

您可以在任何inheritance自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还包含导致validation错误的实体。 所以如果你需要更多的信息,你可以改变上面的代码来输出关于这些实体的信息。

另见: 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); } } 

要查看EntityValidationErrors集合,请将以下“expression式”添加到“监视”窗口。

 ((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors 

我正在使用Visual Studio 2013

当您在catch {...}块内进入debugging模式时,打开“QuickWatch”窗口( ctrl + alt + q )并粘贴到那里:

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

这将允许您深入查看ValidationErrors树。 这是我发现能够即时洞察这些错误的最简单的方法。

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

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

通过在debugging过程中检查错误来快速find有意义的错误消息:

  • 添加快速查看:

     ((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors 
  • 深入到这样的EntityValidationErrors:

    (集合项例如[0])>validation错误>(集合项例如[0])> ErrorMessage

我认为“实际validation错误”可能包含敏感信息,这可能是微软select把它们放在另一个地方(属性)的原因。 这里标出的解决scheme是实用的,但是应该谨慎对待。

我宁愿创build一个扩展方法。 更多的原因:

  • 保持原始的堆栈跟踪
  • 遵循打开/closures的原则(即:我可以使用不同types的日志不同的消息)
  • 在生产环境中,可能存在其他可能引发DbEntityValidationException的地方(即:other dbcontext)。

实际上,这只是validation问题,EF将在对数据库进行任何更改之前首先validation实体属性。 因此,EF会检查该属性的值是否超出范围,例如devise表格时。 Table_Column_UserName是varchar(20)。 但是,在EF中,input的值大于20.或者,在其他情况下,如果列不允许为空值。 因此,在validation过程中,无论您是否要对其进行更改,都必须将值设置为非空列。 我个人,像Leniel Macaferi的回答。 它可以显示validation问题的细节

在你的代码中使用try块

 try { // Your code... // Could also be before try if you know the exception occurs in SaveChanges context.SaveChanges(); } catch (DbEntityValidationException e) { foreach (var eve in e.EntityValidationErrors) { Console.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) { Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage); } } throw; } 

你也可以在这里查看细节

  1. http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/

  2. 一个或多个实体的validation失败。 有关更多详细信息,请参阅“EntityValidationErrors”属性

  3. http://blogs.infosupport.com/improving-dbentityvalidationexception/