Lui*_*cia 767 c# entity-framework entity-framework-4 entity-framework-4.1
我在使用代码优先方法播种数据库时遇到此错误.
一个或多个实体的验证失败.有关详细信息,请参阅"EntityValidationErrors"属性.
说实话,我不知道如何检查验证错误的内容.Visual Studio向我显示它是一个包含8个对象的数组,因此有8个验证错误.
这与我之前的模型有关,但我做了一些修改,我在下面解释:
请原谅我的长代码,但我必须将其全部粘贴.在以下代码的最后一行中抛出异常.
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; }
}
}
Run Code Online (Sandbox Code Playgroud)
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
Sla*_*uma 1197
说实话,我不知道如何检查验证错误的内容.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;
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
虽然调试Debug.Write
可能比Console.WriteLine
所有类型的应用程序更适合,但不仅仅适用于控制台应用程序(感谢@Bart在下面的评论中提供的注释).
对于正在生产并使用Elmah进行异常日志记录的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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
并且SaveChanges
可以通过以下方式覆盖:
public class MyContext : DbContext
{
// ...
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException e)
{
var newException = new FormattedDbEntityValidationException(e);
throw newException;
}
}
}
Run Code Online (Sandbox Code Playgroud)
几点评论:
Elmah在Web界面或已发送的电子邮件中显示的黄色错误屏幕(如果已配置)现在直接在邮件顶部显示验证详细信息.
覆盖Message
自定义异常中的属性而不是覆盖ToString()
具有标准ASP.NET"黄色死亡屏幕(YSOD)"也显示此消息的好处.与Elmah相比,YSOD显然没有使用ToString()
,但两者都显示了Message
属性.
将原始包装DbEntityValidationException
作为内部异常包装可确保原始堆栈跟踪仍然可用并显示在Elmah和YSOD中.
通过在行上设置断点,throw newException;
您可以简单地将newException.Message
属性作为文本进行检查,而不是深入到验证集合中,这有点尴尬,似乎并不适合每个人(请参阅下面的注释).
yoe*_*alb 442
您可以在调试期间从Visual Studio中执行此操作而无需编写任何代码,甚至不是catch块.
只需添加一个名称为的手表:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
Run Code Online (Sandbox Code Playgroud)
watch表达式$exception
显示当前上下文中抛出的任何异常,即使它尚未被捕获并分配给变量.
基于http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/
t_p*_*lus 101
这实际上可以在不必编写代码的情况下完成:
在catch块中,在以下代码行中添加一个断点:
catch (Exception exception)
{
}
Run Code Online (Sandbox Code Playgroud)
现在,如果您将鼠标悬停在exception
其上或将其添加到其中Watch
,然后导航到异常详细信息,如下所示; 您将看到哪个特定列导致问题,因为当违反表约束时通常会发生此错误.
Shi*_*iva 46
以下是如何,您可以检查的内容EntityValidationErrors期间在Visual Studio(而无需编写任何额外的代码),即调试的IDE.
你是对的,Visual Studio调试器的View Details Popup没有显示EntityValidationErrors
集合中的实际错误.
只需在" 快速监视"窗口中添加以下表达式,然后单击" 重新评估".
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
就我而言,看看我如何能够扩展到集合ValidationErrors
List
内部EntityValidationErrors
参考文献: mattrandle.me博客文章,@ yoel的回答
djd*_*wsk 37
要快速查看第一个错误而不添加手表,您可以将其粘贴到立即窗口中:
((System.Data.Entity.Validation.DbEntityValidationException)$exception)
.EntityValidationErrors.First()
.ValidationErrors.First()
Run Code Online (Sandbox Code Playgroud)
小智 15
对于任何工作的人 VB.NET
Try
Catch ex As DbEntityValidationException
For Each a In ex.EntityValidationErrors
For Each b In a.ValidationErrors
Dim st1 As String = b.PropertyName
Dim st2 As String = b.ErrorMessage
Next
Next
End Try
Run Code Online (Sandbox Code Playgroud)
GON*_*ale 12
当您处于catch {...}
块内的调试模式时,打开"QuickWatch"窗口(ctrl+ alt+ q)并粘贴到那里:
((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors
要么:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
如果您不在try/catch中,或者无法访问异常对象.
这将允许您深入到ValidationErrors
树中.这是我发现能够即时了解这些错误的最简单方法.
Gre*_*reg 10
如果您只是捕获一个通用异常,那么将它转换为DbEntityValidationException可能会让您受益.这种类型的异常具有Validation Errors属性,并且继续扩展您的方式,您将找到所有问题.
例如,如果在catch中放置一个断点,则可以将以下内容放入监视中:
((System.Data.Entity.Validation.DbEntityValidationException ) ex)
Run Code Online (Sandbox Code Playgroud)
错误的一个示例是,如果某个字段不允许空值,并且您有一个空字符串,您会看到该字段是必需的.
在调试中,您可以在QuickWatch表达式评估程序输入字段中输入:
context.GetValidationErrors()
Run Code Online (Sandbox Code Playgroud)
也在努力解决这个错误,并且根据此处的主题,这个答案能够找出要复制/粘贴的代码片段,而无需弄清楚必须导入的内容(对于 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Per @ 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 to
bool validateOnSaveEnabledStartState = BaseDB.Configuration.ValidateOnSaveEnabled;
if (validateEntities.HasValue)
BaseDB.Configuration.ValidateOnSaveEnabled = validateEntities.Value;
BaseDB.SaveChanges();
//Revert the validation state when done
if (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);
}
}
Run Code Online (Sandbox Code Playgroud)
我必须在立即窗口中写这个: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]
Run Code Online (Sandbox Code Playgroud)
为了深入到确切的错误!
@Slauma的答案真的很棒但我发现当ComplexType属性无效时它不起作用.
例如,假设您拥有Phone
复杂类型的属性PhoneNumber
.如果AreaCode
属性无效,则属性名称ve.PropertyNames
为"Phone.AreaCode".这会导致调用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());
}
}
Run Code Online (Sandbox Code Playgroud)
使用@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>
Run Code Online (Sandbox Code Playgroud)
只是把我的两分钱丢进...
在我的dbConfiguration.cs中,我想将context.SaveChanges()方法包装到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 file
File.AppendAllLines(@"c:\temp\dbErrors.txt", outputLines);
throw;
}
Run Code Online (Sandbox Code Playgroud)
我发现...当我收到“ EntityValidationErrors”错误时,....我在数据库“ db1”中的表“ tbladdress”中的字段为“ address1”,其大小为100(即地址varchar(100) null),并且我传递的值超过100个字符。这导致在将数据保存到数据库时出错。
因此,您必须检查要传递给该字段的数据。
归档时间: |
|
查看次数: |
683054 次 |
最近记录: |