一个或多个实体的验证失败。有关更多详细信息,请参阅EntityValidationEr的属性

我在使用代码优先方法播种我的数据库时遇到此错误。

一个或多个实体的验证失败。有关更多详细信息,请参阅EntityValidationEr的属性。

老实说,我不知道如何检查验证错误的内容。Visual Studio向我展示了它是一个包含8个对象的数组,因此有8个验证错误。

这与我以前的模型一起工作,但我做了一些更改,我在下面解释:

  • 我有一个名为状态的枚举,我把它改为一个名为状态的类
  • 我改变了类Application antsPositionHistory有2个外键到同一个表

请原谅我的代码很长,但我必须全部粘贴。异常抛出在以下代码的最后一行。

namespace Data.Model{public class Position{[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]public int PositionID { get; set; }
[Required(ErrorMessage = "Position name is required.")][StringLength(20, MinimumLength = 3, ErrorMessage = "Name should not be longer than 20 characters.")][Display(Name = "Position name")]public string name { get; set; }
[Required(ErrorMessage = "Number of years is required")][Display(Name = "Number of years")]public int yearsExperienceRequired { get; set; }
public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }}
public class Applicant{[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]public int ApplicantID { get; set; }
[Required(ErrorMessage = "Name is required")][StringLength(20, MinimumLength = 3, ErrorMessage="Name should not be longer than 20 characters.")][Display(Name = "First and LastName")]public string name { get; set; }
[Required(ErrorMessage = "Telephone number is required")][StringLength(10, MinimumLength = 3, ErrorMessage = "Telephone should not be longer than 20 characters.")][Display(Name = "Telephone Number")]public string telephone { get; set; }
[Required(ErrorMessage = "Skype username is required")][StringLength(10, MinimumLength = 3, ErrorMessage = "Skype user should not be longer than 20 characters.")][Display(Name = "Skype Username")]public string skypeuser { get; set; }
public byte[] photo { get; set; }
public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }}
public class ApplicantPosition{[Key][Column("ApplicantID", Order = 0)]public int ApplicantID { get; set; }
[Key][Column("PositionID", Order = 1)]public int PositionID { get; set; }
public virtual Position Position { get; set; }
public virtual Applicant Applicant { get; set; }
[Required(ErrorMessage = "Applied date is required")][DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)][Display(Name = "Date applied")]public DateTime appliedDate { get; set; }
[Column("StatusID", Order = 0)]public int StatusID { get; set; }
public Status CurrentStatus { get; set; }
//[NotMapped]//public int numberOfApplicantsApplied//{//    get//    {//        int query =//             (from ap in Position//              where ap.Status == (int)Status.Applied//              select ap//                  ).Count();//        return query;//    }//}}
public class Address{[StringLength(20, MinimumLength = 3, ErrorMessage = "Country should not be longer than 20 characters.")]public string Country { get; set; }
[StringLength(20, MinimumLength = 3, ErrorMessage = "City  should not be longer than 20 characters.")]public string City { get; set; }
[StringLength(50, MinimumLength = 3, ErrorMessage = "Address  should not be longer than 50 characters.")][Display(Name = "Address Line 1")]public string AddressLine1 { get; set; }
[Display(Name = "Address Line 2")]public string AddressLine2 { get; set; }}
public class ApplicationPositionHistory{[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]public int ApplicationPositionHistoryID { get; set; }
public ApplicantPosition applicantPosition { get; set; }
[Column("oldStatusID")]public int oldStatusID { get; set; }
[Column("newStatusID")]public int newStatusID { get; set; }
public Status oldStatus { get; set; }
public Status newStatus { get; set; }
[StringLength(500, MinimumLength = 3, ErrorMessage = "Comments  should not be longer than 500 characters.")][Display(Name = "Comments")]public string comments { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)][Display(Name = "Date")]public DateTime dateModified { get; set; }}
public class Status{[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]public int StatusID { get; set; }
[StringLength(20, MinimumLength = 3, ErrorMessage = "Status  should not be longer than 20 characters.")][Display(Name = "Status")]public string status { get; set; }}}

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data.Entity;using System.IO;
namespace Data.Model{public class HRContextInitializer : DropCreateDatabaseAlways<HRContext>{protected override void Seed(HRContext context){#region StatusStatus applied = new Status() { status = "Applied" };Status reviewedByHR = new Status() { status = "Reviewed By HR" };Status approvedByHR = new Status() { status = "Approved by HR" };Status rejectedByHR = new Status() { status = "Rejected by HR" };Status assignedToTechnicalDepartment = new Status() { status = "Assigned to Technical Department" };Status approvedByTechnicalDepartment = new Status() { status = "Approved by Technical Department" };Status rejectedByTechnicalDepartment = new Status() { status = "Rejected by Technical Department" };
Status assignedToGeneralManager = new Status() { status = "Assigned to General Manager" };Status approvedByGeneralManager = new Status() { status = "Approved by General Manager" };Status rejectedByGeneralManager = new Status() { status = "Rejected by General Manager" };
context.Status.Add(applied);context.Status.Add(reviewedByHR);context.Status.Add(approvedByHR);context.Status.Add(rejectedByHR);context.Status.Add(assignedToTechnicalDepartment);context.Status.Add(approvedByTechnicalDepartment);context.Status.Add(rejectedByTechnicalDepartment);context.Status.Add(assignedToGeneralManager);context.Status.Add(approvedByGeneralManager);context.Status.Add(rejectedByGeneralManager);#endregion
#region PositionPosition netdeveloper = new Position() { name = ".net developer", yearsExperienceRequired = 5 };Position javadeveloper = new Position() { name = "java developer", yearsExperienceRequired = 5 };context.Positions.Add(netdeveloper);context.Positions.Add(javadeveloper);#endregion
#region ApplicantsApplicant luis = new Applicant(){name = "Luis",skypeuser = "le.valencia",telephone = "0491732825",photo = File.ReadAllBytes(@"C:\Users\LUIS.SIMBIOS\Documents\Visual Studio 2010\Projects\SlnHR\HRRazorForms\Content\pictures\1.jpg")};
Applicant john = new Applicant(){name = "John",skypeuser = "jo.valencia",telephone = "3435343543",photo = File.ReadAllBytes(@"C:\Users\LUIS.SIMBIOS\Documents\Visual Studio 2010\Projects\SlnHR\HRRazorForms\Content\pictures\2.jpg")};
context.Applicants.Add(luis);context.Applicants.Add(john);#endregion
#region ApplicantsPositionsApplicantPosition appicantposition = new ApplicantPosition(){Applicant = luis,Position = netdeveloper,appliedDate = DateTime.Today,StatusID = 1};
ApplicantPosition appicantposition2 = new ApplicantPosition(){Applicant = john,Position = javadeveloper,appliedDate = DateTime.Today,StatusID = 1};
context.ApplicantsPositions.Add(appicantposition);context.ApplicantsPositions.Add(appicantposition2);#endregion
context.SaveChanges(); --->> Error here}}}
884874 次浏览

老实说,我不知道如何检查验证错误的内容。Visual Studio向我展示了它是一个包含8个对象的数组,因此有8个验证错误。

实际上,如果在调试期间在Visual Studio中钻取该数组,你应该会看到错误。但你也可以捕获异常,然后将错误写入一些日志存储或控制台:

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;}

EntityValidationErrors是一个集合,表示无法成功验证的实体,每个实体的内部集合ValidationErrors是属性级别的错误列表。

这些验证消息通常足以帮助找到问题的根源。

编辑

一些小改进:

违规属性的可以包含在内循环中,如下所示:

        foreach (var ve in eve.ValidationErrors){Console.WriteLine("- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",ve.PropertyName,eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName),ve.ErrorMessage);}

虽然调试Debug.Write可能比Console.WriteLine更可取,因为它适用于所有类型的应用程序,而不仅仅是控制台应用程序(感谢@Bart在下面的评论中的注释)。

对于生产中使用以勒玛进行异常记录的Web应用程序,创建一个自定义异常并覆盖SaveChanges以抛出这个新异常对我来说非常有用。

自定义异常类型如下所示:

public class FormattedDbEntityValidationException : Exception{public FormattedDbEntityValidationException(DbEntityValidationException innerException) :base(null, innerException){}
public override string Message{get{var innerException = InnerException as DbEntityValidationException;if (innerException != null){StringBuilder sb = new StringBuilder();
sb.AppendLine();sb.AppendLine();foreach (var eve in innerException.EntityValidationErrors){sb.AppendLine(string.Format("- Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",eve.Entry.Entity.GetType().FullName, eve.Entry.State));foreach (var ve in eve.ValidationErrors){sb.AppendLine(string.Format("-- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",ve.PropertyName,eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName),ve.ErrorMessage));}}sb.AppendLine();
return sb.ToString();}
return base.Message;}}}

SaveChanges可以通过以下方式覆盖:

public class MyContext : DbContext{// ...
public override int SaveChanges(){try{return base.SaveChanges();}catch (DbEntityValidationException e){var newException = new FormattedDbEntityValidationException(e);throw newException;}}}

几点意见:

  • Elmah在Web界面或发送的电子邮件中显示的黄色错误屏幕(如果您已配置)现在直接在消息顶部显示验证详细信息。

  • 覆盖自定义异常中的Message属性而不是覆盖ToString()的好处是标准ASP.NET“死亡黄屏(YSOD)”也显示此消息。与Elmah相比,YSOD显然不使用ToString(),但两者都显示Message属性。

  • 将原始DbEntityValidationException包装为内部异常可确保原始堆栈跟踪仍然可用,并显示在Elmah和YSOD中。

  • 通过在throw newException;行设置断点,您可以简单地将newException.Message属性作为文本进行检查,而不是钻入验证集合,这有点尴尬,似乎对每个人都不容易工作(请参阅下面的评论)。

请注意,Entity.GetType().BaseType.Name给出了您指定的类型名称,而不是名称中包含所有十六进制数字的类型名称。

在try catch中捕获异常,然后快速观看或ctrl+d&ctrl+q,您可以向下钻取到EntityValidationError。

对于任何在VB.NET工作的人

TryCatch ex As DbEntityValidationExceptionFor Each a In ex.EntityValidationErrorsFor Each b In a.ValidationErrorsDim st1 As String = b.PropertyNameDim st2 As String = b.ErrorMessageNextNextEnd Try

根据@Slauma的回答和@Milton的建议,我已经扩展了我们基类的自定义保存方法,使用try/catch来处理(并因此登录我们的错误日志!)这些类型的异常。

// Where `BaseDB` is your Entities object... (it could be `this` in a different design)public void Save(bool? validateEntities = null){try{//Capture and set the validation state if we decide tobool validateOnSaveEnabledStartState = BaseDB.Configuration.ValidateOnSaveEnabled;if (validateEntities.HasValue)BaseDB.Configuration.ValidateOnSaveEnabled = validateEntities.Value;
BaseDB.SaveChanges();
//Revert the validation state when doneif (validateEntities.HasValue)BaseDB.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabledStartState;}catch (DbEntityValidationException e){StringBuilder sb = new StringBuilder();foreach (var eve in e.EntityValidationErrors){sb.AppendLine(string.Format("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){sb.AppendLine(string.Format("- Property: \"{0}\", Error: \"{1}\"",ve.PropertyName,ve.ErrorMessage));}}throw new DbEntityValidationException(sb.ToString(), e);}}

这实际上可以做到这一点,而无需编写代码:

在捕获块中,在以下代码行处添加断点:

catch (Exception exception){
}

现在,如果您将鼠标悬停在exception或将其添加到Watch,然后导航到异常详细信息,如下所示;您将看到哪个特定列导致问题,因为当违反表约束时通常会发生此错误。

输入图片描述

大图片

如果您只是捕获一个通用异常,将其转换为DB实体验证异常可能会对您有益。这种类型的异常具有验证错误属性,继续扩展到它们中,您将找到所有问题。

例如,如果您在捕获中放置断点,则可以将以下内容扔进手表:

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

错误的一个例子是如果一个字段不允许空值,并且您有一个空字符串,您将看到它说该字段是必需的。

您可以在调试过程中从Visual Studio执行此操作,而无需编写任何代码,甚至无需编写捕获块。

只需添加一个名称为:

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

监视表达式$exception显示在当前上下文中抛出的任何异常,即使它没有被捕获并分配给变量。

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

使用@Slauma的答案,我制作了一个代码片段(带有片段的环绕)以更好地使用。

<?xml version="1.0" encoding="utf-8"?><CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"><CodeSnippet Format="1.0.0"><Header><SnippetTypes><SnippetType>SurroundsWith</SnippetType></SnippetTypes><Title>ValidationErrorsTryCatch</Title><Author>Phoenix</Author><Description></Description><HelpUrl></HelpUrl><Shortcut></Shortcut></Header><Snippet><Code Language="csharp"><![CDATA[try{$selected$ $end$}catch (System.Data.Entity.Validation.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;}]]></Code></Snippet></CodeSnippet></CodeSnippets>

当您在catch {...}块中处于调试模式时,打开“QuickWatch”窗口(ctrl+alt+q)并粘贴到那里:

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

或:

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

如果您不在try/catch中或无权访问异常对象。

这将允许您向下钻取ValidationErrors树。这是我发现的即时了解这些错误的最简单方法。

要快速查看第一个错误,甚至无需添加手表,您可以将其粘贴到立即窗口中:

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

只需检查您的数据库表字段长度。您的输入文本大于列字段数据类型长度

我不得不在即时窗口中写这个:3

(((exception as System.Data.Entity.Validation.DbEntityValidationException).EntityValidationErrors as System.Collections.Generic.List<System.Data.Entity.Validation.DbEntityValidationResult>)[0].ValidationErrors as System.Collections.Generic.List<System.Data.Entity.Validation.DbValidationError>)[0]

为了深入准确的错误!

来自@Slauma的答案真的很棒,但我发现当ComplexType属性无效时它不起作用。

例如,假设您有一个复杂类型PhoneNumber的属性Phone。如果AreaCode属性无效,则ve.PropertyNames中的属性名称为“Phone. Area aCode”。这会导致对eve.Entry.CurrentValues<object>(ve.PropertyName)的调用失败。

要解决此问题,您可以在每个.处拆分属性名称,然后递归遍历生成的属性名称数组。最后,当您到达链的底部时,您可以简单地返回属性的值。

下面是@Slauma的FormattedDbEntityValidationException类,支持ComplexTypes。

好好享受!

[Serializable]public class FormattedDbEntityValidationException : Exception{public FormattedDbEntityValidationException(DbEntityValidationException innerException) :base(null, innerException){}
public override string Message{get{var innerException = InnerException as DbEntityValidationException;if (innerException == null) return base.Message;
var sb = new StringBuilder();
sb.AppendLine();sb.AppendLine();foreach (var eve in innerException.EntityValidationErrors){sb.AppendLine(string.Format("- Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",eve.Entry.Entity.GetType().FullName, eve.Entry.State));foreach (var ve in eve.ValidationErrors){object value;if (ve.PropertyName.Contains(".")){var propertyChain = ve.PropertyName.Split('.');var complexProperty = eve.Entry.CurrentValues.GetValue<DbPropertyValues>(propertyChain.First());value = GetComplexPropertyValue(complexProperty, propertyChain.Skip(1).ToArray());}else{value = eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName);}sb.AppendLine(string.Format("-- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",ve.PropertyName,value,ve.ErrorMessage));}}sb.AppendLine();
return sb.ToString();}}
private static object GetComplexPropertyValue(DbPropertyValues propertyValues, string[] propertyChain){var propertyName = propertyChain.First();return propertyChain.Count() == 1? propertyValues[propertyName]: GetComplexPropertyValue((DbPropertyValues)propertyValues[propertyName], propertyChain.Skip(1).ToArray());}}

在调试中,您可以在QuickWatch表达式求值器输入字段中输入:

context.GetValidationErrors()

这对我有用。

var modelState = ModelState.Values;if (!ModelState.IsValid){return RedirectToAction("Index", "Home", model);}

在if语句上设置断点。然后您可以在调试窗口中检查模型状态。在每个值上,您都可以看到是否有错误,甚至错误消息。就是这样。当你不再需要它时,只需删除或注释该行。

我希望这会有帮助。

如果被问到,我可以在调试窗口中提供详细的屏幕截图。

正如其他文章中提到的,只需捕获DbEntityValidationException类中的异常。这将为您提供错误情况下所需的水。

 try{....}catch(DbEntityValidationException ex){....}

我以前也犯过这个错误

当我试着在实体框架中更新我的模型中的特定字段

Letter letter = new Letter {ID = letterId, ExportNumber = letterExportNumber,EntityState = EntityState.Modified};LetterService.ChangeExportNumberfor(letter);//----------

public int ChangeExportNumber(Letter letter){int result = 0;using (var db = ((LettersGeneratorEntities) GetContext())){db.Letters.Attach(letter);db.Entry(letter).Property(x => x.ExportNumber).IsModified = true;result += db.SaveChanges();}return result;}

根据上面的答案

我找到了验证消息The SignerName field is required.

指向我模型中的场

当我检查我的数据库模式时,我发现

在此处输入图片描述

所以0号有权利筹集资金

根据这个字段,我希望它可以为空,(我不知道我是怎么搞砸的)

所以我更改了该字段以允许Null,这样我的代码就不会再给我这个错误了

因此,如果您使数据库的数据完整性无效,可能会发生此错误

以下是如何在Visual Studio中检查实体验证错误的内容(无需编写任何额外代码),即在IDE中的调试期间。

问题?

你是对的,Visual Studio调试器的查看详情弹出窗口不会显示EntityValidationErrors集合中的实际错误。

在此处输入图片描述

解决方案!

只需在快速观察窗口中添加以下表达式并单击重新评估

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

在我的例子中,看看我如何能够扩展到EntityValidationErrors集合中的ValidationErrorsList

在此处输入图片描述

参考文献:mattrandle.me博客文章@张扬的回答

把我的两分钱扔进去…

在我的dbConfiguration.cs中,我喜欢将我的text. SaveChange()方法包装到try/catch中,并生成一个输出文本文件,允许我清楚地读取错误,并且此代码还为它们添加时间戳-如果您在不同时间遇到多个错误,则非常方便!

        try{context.SaveChanges();}catch (DbEntityValidationException e){//Create empty list to capture Validation error(s)var outputLines = new List<string>();
foreach (var eve in e.EntityValidationErrors){outputLines.Add($"{DateTime.Now}: Entity of type \"{eve.Entry.Entity.GetType().Name}\" in state \"{eve.Entry.State}\" has the following validation errors:");outputLines.AddRange(eve.ValidationErrors.Select(ve =>$"- Property: \"{ve.PropertyName}\", Error: \"{ve.ErrorMessage}\""));}//Write to external fileFile.AppendAllLines(@"c:\temp\dbErrors.txt", outputLines);throw;}

我发现…当我得到'EntityValidationEr的错误是…我有一个字段在我的数据库'db1'在表'tbldale'作为'address1'的大小为100(即地址varchar(100)null),我传递值超过100个字符…

因此,您必须检查传递给字段的数据。

请检查您传递的字段值是否有效并与数据库字段一致。例如,在特定字段中传递的字符数小于数据库表字段中定义的字符数。

检查表列中是否有Not Null约束,并且在插入/更新操作时没有传递该列的值。这在实体框架中导致此异常。

如果你使用IISWindows身份验证实体框架,小心使用authorize

我尝试在没有授权的情况下POST,它不起作用,并在db.SaveChangesAsync();上得到这个错误,而所有其他动词GETDELETE都在工作。

但是当我添加AuthorizeAtium作为注释时,它起作用了。

[Authorize]public async Task<IHttpActionResult> Post(...){....}

这是另一种方法,而不是使用Foreach循环来查看EntityValidationError内部。当然,您可以根据自己的喜好格式化消息:

try {// your code goes here...}catch (DbEntityValidationException ex){Console.Write($"Validation errors: {string.Join(Environment.NewLine, ex.EntityValidationErrors.SelectMany(vr => vr.ValidationErrors.Select(err => $"{err.PropertyName} - {err.ErrorMessage}")))}", ex);throw;}

我也遇到了同样的问题。在异常消失后,我从数据库中更新了我的. edmx。

发生此错误主要是因为字段大小。检查数据库表中的所有字段大小。

在我的情况下,这是因为数据库字段的长度小于输入字段的长度。

数据库表

create table user(Username nvarchar(5) not  null);

我的输入

User newUser = new User(){Username = "123456"};

Usernamelength的值是5,即lessthan 6

…这也许能帮到别人

也在努力解决这个错误,并且基于这里的主题,这个答案能够找出要复制/粘贴的片段,而无需弄清楚必须导入什么(非常适合C#初学者),代码如下:

try{context.SaveChanges();}catch (System.Data.Entity.Validation.DbEntityValidationException ex){foreach (var entityValidationErrors in ex.EntityValidationErrors){foreach (var validationError in entityValidationErrors.ValidationErrors){System.Diagnostics.Debug.WriteLine("Property: " + validationError.PropertyName + " Error: " + validationError.ErrorMessage);}}}