发布日期:2018-03-26
对一个或多个实体的验证失败。有关详细信息,请参见“EntityValidationErrors”属性。+ 查看更多
对一个或多个实体的验证失败。有关详细信息,请参见“EntityValidationErrors”属性。
+ 查看更多
发布日期:2018-02-23 13:36
分类:C#
浏览次数:97
当我第一次用种子文件部署数据库的时候出了这个问题
对一个或多个实体的验证失败。有关详细信息,请参见“EntityValidationErrors”属性。
实际上我不知道怎么查看这个验证错误的具体内容,Visual Studio 提示这是一个存有8个对象的数组
之前这个还是正常的,但自从我对它做了这些变动之后就出错了:
我有一个枚举类型叫Status,我把它改成了一个类Status
我给类ApplicationPositionHistory在同一个表里增加了两个外键 不好意思下面的代码很长,但我不得不这样贴代码。异常是在代码最后一行抛出的:
之前这个还是正常的,但自从我对它做了这些变动之后就出错了:
我有一个枚举类型叫Status,我把它改成了一个类Status
我给类ApplicationPositionHistory在同一个表里增加了两个外键 不好意思下面的代码很长,但我不得不这样贴代码。异常是在代码最后一行抛出的:
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 ICollectionapplicantPosition { 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 { 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{ protected override void Seed(HRContext context) { #region Status Status 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 Position Position 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 Applicants Applicant 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 ApplicantsPositions ApplicantPosition 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 } } }
回答:
To be honest I dont know how to check the content of the validation errors, Visual Studio shows me that its an array with 8 objects. so 8 validation Errors.
实际上,如果调试过程中在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
在Debug的时候,写入文件要比打印在控制台好一点。
不仅仅是控制台应用,所有类型的应用都应该写入文件(感谢@Bart在评论区的提醒)。
有些web应用通过Elmah生成异常日志,就我而言比较喜欢创建一个自定义的异常类并重写它的SaveChanges方法来抛出异常
这个自定义类就像这样
不仅仅是控制台应用,所有类型的应用都应该写入文件(感谢@Bart在评论区的提醒)。
有些web应用通过Elmah生成异常日志,就我而言比较喜欢创建一个自定义的异常类并重写它的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
然后重写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)”也会显示这个信息。
因为YSOD与Elmah不同,YSOD不调用ToString(),但它们都会显示Message属性。
将原始的DbEntityValidationException包装成一个内部异常类,可确保原来的堆栈跟踪仍然有效,并显示在Elmah和YSOD中。
通过在一句throw newException就可以设置一个断点,
这样您就可以很容易地查看转化为文本的newException.Message属性,而不是去研究那个验证集合。
但这个办法似乎并不适合所有人(见下面的评论),这就比较尴尬了。