从 DbValidationException 获取准确的错误类型
Posted
技术标签:
【中文标题】从 DbValidationException 获取准确的错误类型【英文标题】:Getting exact error type in from DbValidationException 【发布时间】:2011-07-17 18:47:27 【问题描述】:我有这样的情况,我在 DatabaseInitializer() 中为 EF 4.1 初始化我的模型并得到这个恼人的错误 "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details."
所以,我去这个 EntityValidationErrors 并且有一个字段 System.Data.Entity.Validation.DbEntityValidationResult
没有给我任何信息所有关于它无法初始化的字段。
有没有办法获得有关此错误的更多信息?
清除问题:
我知道如何解决字符串长度问题。我要问的是如何获得破坏模型的确切字段名称。
【问题讨论】:
【参考方案1】:验证您尝试保存的所有不可为空的字段是否具有值。实际上,这可能比找出神秘的错误消息花费的时间更少。
【讨论】:
看来答案可能是对问题的答复。【参考方案2】:我知道这是一个老问题,但这是我的答案:
catch (DbEntityValidationException ex)
String.Join("\n", ex.EntityValidationErrors
.SelectMany(x => x.ValidationErrors)
.Select(x => x.ErrorMessage)
.ToArray());
如果您首先使用代码,您还可以使用多个资源文件来全球化您的错误消息
例如,我有这两个单独的资源文件,一个用于错误,一个用于属性名称,我使用它们如下:
public class Person
[Required(ErrorMessageResourceName = "required",ErrorMessageResourceType =typeof(ErrorMessages))]
[MaxLength(100,ErrorMessageResourceName = "maxLength", ErrorMessageResourceType = typeof(ErrorMessages))]
[Display(Name = "FirstName",ResourceType = typeof(Properties))]
public string FirstName get; set;
如您所见,我已经完全翻译了包括属性名称在内的错误消息,因此我可以稍后在用户中使用它们:
【讨论】:
【参考方案3】:我认为最好的解决方案是集中处理此类错误。
只需将此方法添加到主DbContext
类:
public override int SaveChanges()
try
return base.SaveChanges();
catch (DbEntityValidationException ex)
string errorMessages = string.Join("; ", ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.PropertyName + ": " + x.ErrorMessage));
throw new DbEntityValidationException(errorMessages);
这将覆盖您的上下文的 SaveChanges()
方法,您将获得一个逗号分隔的列表,其中包含所有实体验证错误。
希望这有帮助。
【讨论】:
使用此字符串创建一个字符串。错误属性和消息的Join() 有助于在错误记录系统中使用。【参考方案4】:我发现创建一个 SaveChanges 包装器很有用,它使 EntityValidationErrors 更具可读性:
Public Sub SaveChanges(entities As Entities)
Try
entities.SaveChanges()
Catch ex As DbEntityValidationException
Dim msg As New StringBuilder
msg.AppendLine(ex.Message)
For Each vr As DbEntityValidationResult In ex.EntityValidationErrors
For Each ve As DbValidationError In vr.ValidationErrors
msg.AppendLine(String.Format("0: 1", ve.PropertyName, ve.ErrorMessage))
Next
Next
Throw New DbEntityValidationException(msg.ToString, ex.EntityValidationErrors, ex)
End Try
End Sub
然后在我的整个项目中将 'entities.SaveChanges()' 更改为 'SaveChanges(entities)'
【讨论】:
【参考方案5】:当您在catch ...
块内处于调试模式时,打开“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
【讨论】:
如果没有catch块,可以将ex
替换为$exception
,得到同样的结果。
还要确保将 ex
替换为您的 catch (Exception THIS)
@Ecyrb,谢谢。您节省了数小时的谷歌搜索时间。另外,即使验证错误计数显示为 1,实际上数组中有两个元素有两个错误。
这对我不起作用(VS2015)“错误 CS0103:当前上下文中不存在名称 '$exception'”
对于那些不引用 System.Linq 并使用即时窗口的人:System.Linq.Enumerable.ToList(System.Linq.Enumerable.ToList(((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors)[0].ValidationErrors)[0].ErrorMessage
【参考方案6】:
你可以在 try/catch 块中试试这个吗?
catch (DbEntityValidationException dbEx)
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
Trace.TraceInformation("Property: 0 Error: 1", validationError.PropertyName, validationError.ErrorMessage);
【讨论】:
【参考方案7】:嗯,我也有同样的问题。我的模型在 EF CTP5 中运行良好,但未能在 4.1 中构建,当我尝试初始化它时出现相同的错误““一个或多个实体的验证失败”。我发现我有财产:
public string Comment get; set;
然后在重写初始化程序中的种子方法中,我有相当长(大约 600 个字母)的评论。
我认为重点是:在 EF 4.1 中,您必须在某些情况下明确设置数据注释。对我来说,设置:
[StringLength(4000)]
public string Comment get; set;
帮助。这很奇怪,因为 CTP5 对此没有任何问题。
【讨论】:
好吧,我要问的是如何获得破坏模型的确切属性名称。不过,我设法克服了你所说的问题,使用 [StringLength(Int32.MaxValue)] 作为我的属性的属性(正如 Ladislav Mrnka 所建议的,我在这个问题***.com/questions/5346155/… 中谈到了它)Powodzenia! =) 当我在 4.1 中向我的模型添加新属性时抛出了这个问题。之前在 4.1 中完美运行。诡异的。通过为模型中的所有属性添加注释来解决。以上是关于从 DbValidationException 获取准确的错误类型的主要内容,如果未能解决你的问题,请参考以下文章
从一个触发器,如何找出谁修改了表X上的数据,同时该用户从一个通用的dbuser登录,但从用户表获得了权利
为啥我们要包装 HttpServletRequest ? api 提供了一个 HttpServletRequestWrapper 但我们从包装请求中获得了啥?