코드 우선 접근 방식으로 데이터베이스를 시드 할 때이 오류가 발생합니다.
하나 이상의 엔터티에 대한 유효성 검사에 실패했습니다. 자세한 내용은 ‘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
}
}
}
답변
솔직히 유효성 검사 오류의 내용을 확인하는 방법을 모르겠습니다. 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 덕분에).
프로덕션 환경에 있고 예외 로깅에 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<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가 웹 인터페이스 또는 전송 된 전자 메일 (구성한 경우)에 표시되는 노란색 오류 화면에 메시지 상단에 직접 유효성 검사 세부 정보가 표시됩니다.
-
덮어 쓰기
Message
대신 사용자 지정 예외에서 속성을 덮어 쓰면ToString()
표준 ASP.NET “YSOD (Yellow screen of death)”도이 메시지를 표시하는 이점이 있습니다. Elmah와 달리 YSOD는 분명히을 사용하지ToString()
않지만 둘 다Message
속성을 표시합니다 . -
원본
DbEntityValidationException
을 내부 예외로 래핑하면 원본 스택 추적을 계속 사용할 수 있으며 Elmah 및 YSOD에 표시됩니다. -
줄에 중단 점을 설정하면 약간 어색하고 모든 사람에게 쉽게 작동하지 않는 유효성 검사 모음으로 드릴하는 대신 속성을 텍스트로
throw newException;
간단하게 검사 할 수 있습니다newException.Message
(아래 주석 참조).
답변
catch 블록이 아닌 코드를 작성하지 않고도 디버깅 중에 Visual Studio에서이를 수행 할 수 있습니다.
이름이있는 시계를 추가하기 만하면됩니다.
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
watch 표현식 $exception
은 변수에 지정되지 않았거나 현재 컨텍스트에서 발생한 예외를 표시합니다.
http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/ 기반
답변
실제로 코드를 작성하지 않고도 수행 할 수 있습니다.
캐치 블록에서 다음 코드 줄에 중단 점을 추가하십시오.
catch (Exception exception)
{
}
이제 위에 마우스를 올려 exception
놓거나에 추가 Watch
한 다음 아래에 표시된 예외 세부 정보를 탐색하십시오. 이 오류는 일반적으로 테이블 제약 조건을 위반할 때 발생하므로 어떤 특정 열에서 문제를 일으키는 지 알 수 있습니다.
답변
다음 은 IDE 에서 디버깅 하는 동안 (추가 코드를 작성하지 않고) Visual Studio 에서 EntityValidationErrors 의 내용을 확인하는 방법 입니다.
문제?
맞습니다 .Visual Studio 디버거의 세부 정보보기 팝업에는 EntityValidationErrors
컬렉션 내부의 실제 오류가 표시되지 않습니다 .
해결책!
Quick Watch 창 에 다음 표현식을 추가하고 재평가를 클릭하십시오 .
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
내 경우 ValidationErrors
List
에는 EntityValidationErrors
컬렉션 내부 로 확장하는 방법을 참조하십시오
참고 문헌 : mattrandle.me 블로그 게시물 , @yoel 의 답변
답변
시계를 추가하지 않고도 첫 번째 오류를 빠르게 확인할 수있는 방법은 직접 실행 창에 붙여 넣을 수 있습니다.
((System.Data.Entity.Validation.DbEntityValidationException)$exception)
.EntityValidationErrors.First()
.ValidationErrors.First()
답변
일하는 사람을 위해 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
답변
catch {...}
블록 내에서 디버그 모드에있는 동안 “QuickWatch”창 ( ctrl+ alt+ q)을 열고 여기에 붙여 넣으십시오.
((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors
또는:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
try / catch에 없거나 예외 개체에 액세스 할 수없는 경우
그러면 ValidationErrors
트리 로 드릴 다운 할 수 있습니다 . 이 오류에 대한 즉각적인 통찰력을 얻는 가장 쉬운 방법입니다.