我在使用代码优先方法播种数据库时遇到此错误 .
一个或多个实体的验证失败 . 有关详细信息,请参阅“EntityValidationErrors”属性 .
说实话,我不知道如何检查验证错误的内容 . Visual Studio向我显示它是一个包含8个对象的数组,因此有8个验证错误 .
这与我以前的模型有关,但我做了一些修改,我在下面解释:
-
我有一个名为Status的枚举,我将其更改为名为Status的类
-
我将类ApplicantsPositionHistory更改为在同一个表中有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 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
}
}
}
25 回答
对于在
VB.NET
工作的任何人把我的两分钱扔进......
在我的dbConfiguration.cs中,我喜欢将我的context.SaveChanges()方法包装到try / catch中并生成一个输出文本文件,允许我清楚地读取错误,这段代码也为它们加上时间戳 - 如果你方便的话在不同的时间遇到多个错误!
使用@Slauma的答案,我已经制作了一个代码片段(带有代码片段的环绕声),以便更好地使用 .
在调试中,您可以在QuickWatch表达式评估程序输入字段中输入:
实际上,如果在调试期间在Visual Studio中钻入该数组,则应该看到错误 . 但您也可以捕获异常,然后将错误写入某些日志存储或控制台:
EntityValidationErrors
是一个集合,表示无法成功验证的实体,每个实体的内部集合ValidationErrors
是属性级别的错误列表 .这些验证消息通常足以找到问题的根源 .
Edit
一些小改进:
有问题的属性的值可以包含在内部循环中,如下所示:
虽然调试
Debug.Write
可能优于Console.WriteLine
,因为它适用于所有类型的应用程序,不仅适用于控制台应用程序(感谢@Bart在下面的评论中的注释) .对于正在 生产环境 中并使用 Elmah 进行异常日志记录的Web应用程序,对我来说,创建自定义异常并覆盖
SaveChanges
以便抛出此新异常非常有用 .自定义异常类型如下所示:
并且
SaveChanges
可以通过以下方式覆盖:几点评论:
Elmah在Web界面或已发送的电子邮件中显示的黄色错误屏幕(如果已配置)现在直接在邮件顶部显示验证详细信息 .
覆盖自定义异常中的
Message
属性而不是覆盖ToString()
,这样做的好处是标准ASP.NET "Yellow screen of death (YSOD)"也显示此消息 . 与Elmah相比,YSOD显然不使用ToString()
,但两者都显示Message
属性 .将原始
DbEntityValidationException
包装为内部异常可确保原始堆栈跟踪仍然可用并显示在Elmah和YSOD中 .通过在
throw newException;
行上设置断点,您只需将newException.Message
属性视为文本,而不是深入到验证集合中,这有点尴尬,似乎并不适合所有人(请参阅下面的注释) .请检查您传递的字段值是否有效以及根据数据库字段 . 例如,在特定字段中传递的字符数小于在数据库表字段中定义的字符数 .
如果您使用 IIS 与 Windows Authentification 和 Entity Framework ,请小心使用
authorize
.我试图
POST
没有授权,它没有工作,并在db.SaveChangesAsync();
上得到此错误,而所有其他动词GET
和DELETE
正在工作 .但是当我添加AuthorizeAttribute作为注释时,它起作用了 .
这实际上可以在不必编写代码的情况下完成:
在catch块中,在以下代码行中添加一个断点:
现在,如果您将鼠标悬停在
exception
上或将其添加到Watch
,然后导航到异常详细信息,如下所示;您将看到哪个特定列导致问题,因为当违反表约束时通常会发生此错误 .Large image
在try catch中捕获异常,然后快速监视或按住Ctrl键,您可以深入查看EntityValidationErrors .
只需检查数据库表字段长度 . 输入文本大于列字段数据类型长度
要快速查看第一个错误而不添加 Watch ,您可以将其粘贴到立即数中窗口:
这对我有用 .
在if语句上加上断点 . 然后,您可以在调试窗口中检查modelState . 如果出现错误甚至错误消息,您可以看到每个值 . 而已 . 如果您不再需要它,只需删除或注释该行 .
我希望这将有所帮助 .
如果被问到,我可以在调试窗口中提供详细的屏幕截图 .
您可以在调试期间从Visual Studio中执行此操作而无需编写任何代码,甚至不能使用catch块 .
只需添加一个名称为的 Watch :
监视表达式
$exception
显示当前上下文中抛出的任何异常,即使它尚未被捕获并分配给变量 .基于http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/
我必须在立即窗口中写这个:3
为了深入了解确切的错误!
@Slauma的答案真的很棒,但我发现当ComplexType属性无效时它不起作用 .
例如,假设您拥有复杂类型
PhoneNumber
的属性Phone
. 如果AreaCode
属性无效,则ve.PropertyNames
中的属性名称为"Phone.AreaCode" . 这会导致对eve.Entry.CurrentValues<object>(ve.PropertyName)
的调用失败 .要解决此问题,您可以在每个
.
拆分属性名称,然后通过生成的属性名称数组进行递归 . 最后,当您到达链的底部时,您只需返回属性的值即可 .下面是@ Slauma的
FormattedDbEntityValidationException
类,支持ComplexTypes .请享用!
如果您只是捕获一个通用异常,那么将其转换为 DbEntityValidationException 可能会对您有所帮助 . 这种类型的异常具有Validation Errors属性,并继续扩展您的方式,您将找到所有问题 .
例如,如果在catch中放置一个断点,则可以将以下内容放入监视中:
错误的一个例子是 if a field does not allow nulls, and you have a null string, you'll see it say that the field is required.
检查表列中是否有
Not Null
约束,并且在插入/更新操作时不传递该列的值 . 这导致实体框架中的此异常 .当你处于
catch {...}
块内的调试模式时,打开"QuickWatch"窗口(ctrl alt q)并粘贴到那里:((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors
要么:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
如果您不在try / catch中,或者无法访问异常对象 .
这将允许您深入查看
ValidationErrors
树 . 它已被发现可以立即了解这些错误 .我之前遇到过这个错误
当我试着update specific field in my model in entity framwork
并根据上述答案
我找到了验证消息
The SignerName field is required.
它指向我模型中的字段
当我检查我的数据库架构时,我找到了
所以关闭coure
ValidationException
有权提出根据这个领域,我希望它可以为空,(我不知道我是怎么搞砸的)
所以我改变了那个字段以允许Null,由此我的代码不再给我这个错误
这是另一种方法,而不是使用foreach循环来查看EntityValidationErrors . 当然,您可以根据自己的喜好格式化消息:
我发现的......当我得到'EntityValidationErrors'错误是....我在表'tbladdress'的数据库'db1'中有一个字段为'address1',其大小为100(即地址varchar(100) null),我传递的值超过100个字符..这导致错误,同时将数据保存到数据库....
因此,您必须检查要传递到该字段的数据 .
以下是如何检查Visual Studio中 EntityValidationErrors 的内容(无需编写任何额外代码),即在 IDE 中 Debugging 期间 .
问题?
你是对的,Visual Studio调试器的 View Details Popup没有显示
EntityValidationErrors
集合中的实际错误 .解决方案!
只需在 Quick Watch 窗口中添加以下表达式,然后单击 Reevaluate .
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
就我而言,看看我如何能够扩展到
EntityValidationErrors
集合中的ValidationErrors
List
References: mattrandle.me blog post,@yoel's answer
正如其他帖子中所提到的,只需在DbEntityValidationException类中捕获异常即可 . 这将为您提供错误案例中所需的watever .
Per @ Slauma的答案和@Milton的建议我用一个try / catch扩展了我们的基类的自定义保存方法,它将处理(并因此登录我们的错误记录!)这些异常 .
请注意,
Entity.GetType().BaseType.Name
给出了您指定的类型名称,而不是名称中包含所有十六进制数字的名称 .