DbEntityValidationException – 如何轻松地告诉造成错误的原因?
我有一个使用entity framework的项目。 在我的DbContext
上调用SaveChanges
时,出现以下exception:
System.Data.Entity.Validation.DbEntityValidationException:一个或多个实体的validation失败。 有关更多详细信息,请参阅“EntityValidationErrors”属性。
这一切都很好,但我不希望每当发生这种exception时都附加一个debugging器。 更重要的是,在生产环境中,我不能轻易地附加一个debugging器,所以我必须竭尽全力去重现这些错误。
我如何看到隐藏在DbEntityValidationException
的细节?
最简单的解决scheme是在您的实体类上重写SaveChanges
。 您可以捕获DbEntityValidationException
,解开实际的错误,并使用改进的消息创build新的DbEntityValidationException
。
- 在SomethingSomething.Context.cs文件旁边创build一个部分类。
- 使用这篇文章底部的代码。
- 而已。 您的实现将自动使用重写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; }
你也可以在这里查看细节
-
http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/
-
一个或多个实体的validation失败。 有关更多详细信息,请参阅“EntityValidationErrors”属性
-
http://blogs.infosupport.com/improving-dbentityvalidationexception/