EF 코드 우선 : 너겟 패키지 콘솔에서 'EntityValidationErrors'속성을 어떻게 볼 수 있습니까?


127

나는 이것을 잃어 버렸다.

엔티티 프레임 워크 (4.1.3) 코드 첫 번째 접근 방식에 대한 클래스를 정의했습니다. 내가 씨앗을 시작할 때까지 모든 것이 잘되었습니다 (테이블 등을 만들고있었습니다).

이제 내가 할 때

Add-Migration "remigrate" ; Update-Database;

패키지 콘솔에 "하나 이상의 엔터티에 대한 유효성 검사에 실패했습니다. 자세한 내용은 'EntityValidationErrors'속성을 참조하십시오."라는 오류가 발생합니다.

내 Seed () 메서드에 중단 점이 있지만 프로젝트가 실행되고 있지 않을 때 콘솔에서이를 실행하기 때문에 세부 정보를 얻는 방법에 대한 단서가 없습니다 (PS-스레드 유효성 검사에 실패했습니다. Entity Framework사용하여 SQL Server 데이터베이스에 변경 사항을 저장하는 동안 하나 이상의 엔터티에 대해 속성을 볼 수있는 방법을 보여줍니다.)

메서드 호출 직후에 반환하면 오류가 사라지기 때문에 Seed () 메서드에 문제가 있음을 알고 있습니다. 그렇다면 유효성 검사 오류가 무엇인지 알 수 있도록 중단 점을 어떻게 설정합니까? 졌어요 아니면 너겟 콘솔에서 추적 할 수있는 다른 방법이 있습니까 ??


빠른 업데이트 : 오류의 원인을 찾을 때까지 내 메소드 내의 각 변수를 체계적으로 추적하여 문제를 해결했습니다. 그러나 여전히 질문에 대한 답을 알고 싶습니다.
jeremy

프로그래밍 방식으로 마이그레이션을 실행 한 다음 예외를 포착하고 오류를 반복 할 수 있다고 생각합니다. 이상적이지는 않지만 필요한 세부 정보를 제공 할 수 있습니다.
Pawel

정답이 정답 일 때 좌절하고 모든 크레딧을 얻습니다. StackOverflow가 분명히 부족한 곳!
jwize

Entity Framework 를 사용하는 경우 "하나 이상의 엔터티에 대한 유효성 검사에 실패했습니다." 에 대한 솔루션 에서 내 대답을 볼 수 있습니다 . 자세한 내용은 'EntityValidationErrors'속성을 참조하십시오 . 희망이 ...하는 데 도움이
무라트하기 Yıldız

답변:


216

최근에도 이것에 짜증이났습니다. Seed 메서드의 Configuration 클래스에 래퍼 함수를 ​​넣어서 수정하고 SaveChanges대신 호출을 내 함수 호출로 대체 했습니다. 이 함수는 단순히 EntityValidationErrors콜렉션 내의 오류를 열거 하고 예외 메시지가 개별 문제점을 나열하는 예외를 다시 발생시킵니다. 그러면 NuGet 패키지 관리자 콘솔에 출력이 표시됩니다.

코드는 다음과 같습니다.

/// <summary>
/// Wrapper for SaveChanges adding the Validation Messages to the generated exception
/// </summary>
/// <param name="context">The context.</param>
private void SaveChanges(DbContext context) {
    try {
        context.SaveChanges();
    } catch (DbEntityValidationException ex) {
        StringBuilder sb = new StringBuilder();

        foreach (var failure in ex.EntityValidationErrors) {
            sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
            foreach (var error in failure.ValidationErrors) {
                sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                sb.AppendLine();
            }
        }

        throw new DbEntityValidationException(
            "Entity Validation Failed - errors follow:\n" + 
            sb.ToString(), ex
        ); // Add the original exception as the innerException
    }
}

seed 메소드에서 호출을 context.SaveChanges()로 바꾸 SaveChanges(context)십시오.


리차드! 아이디어가있는 사람. 시도하면이 질문으로 돌아올 것입니다.
jeremy

이것은 정말로 nasties를 추적하는 데 도움이됩니다 :)
Eminem

3
이 기술을 사용했지만 대신 컨텍스트 내에서 savechanges 재정의를 사용했습니다. public override int SaveChanges() 맥락 안에서.
Kirsten Greed

5
아래 답변 한대로 부분 클래스를 사용하는 것이 더 효과적입니다.
jwize

1
시드 메서드에서 UserManager 작업을 수행하는 경우이 변경 사항에 출력에 유효성 검사 오류가 포함되지 않으므로 @jwize 답변에 따라 DBContext SaveChanges, SaveChangesAsync 및 SaveChangesAsync (CT) 메서드를 재정의해야합니다.
Carl

115

부분 클래스 정의로 DBContext 클래스를 이미 확장하십시오!

DbContext의 클래스 정의를 보면 다음과 같습니다.

// DatabaseContext.cs   -- This file is auto generated and thus shouldn't be changed. 
public partial class [DatabaseContextName] : DbContext { ... }

따라서 다른 파일에서 동일한 정의를 작성하고 원하는 부분을 대체 할 수 있습니다.

// partialDatabaseContext.cs  -- you can safely make changes 
// that will not be overwritten in here.
public partial class [DatabaseContextName] : DbContext { // Override defaults here } 

부분 클래스와 전체 아이디어는 당신이 알 --did DbContext이 부분 그 수업은 당신이 생성 된 클래스를 확장 (또는 여러 개의 파일로 클래스를 구성하는) 우리의 경우 우리는 또한 할 수 있다는 것입니다 오버라이드 (override) SaveChanges를의 방법을 DbContext에 추가하는 부분 클래스 내에서 .

이 방법으로 모든 기존 DbContext / SaveChanges 호출에서 오류 디버깅 정보를 얻을 수 있으며 시드 코드 또는 개발 코드를 전혀 변경할 필요가 없습니다.

이것은 (내가 할 것 인 것이다 참고 차이가 난 그냥 저작 우리 자신에 SaveChanges를 메소드를 오버라이드 (override)이다 DbContext에게 부분 클래스, NOT 생성 된 하나 ). 또한 부분 클래스가 올바른 네임 스페이스를 사용하는지 확인하십시오. 그렇지 않으면 벽에 머리가 부딪 칠 것입니다.

public partial class Database : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            var sb = new StringBuilder();

            foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
                foreach (var error in failure.ValidationErrors)
                {
                    sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine();
                }
            }

            throw new DbEntityValidationException(
                "Entity Validation Failed - errors follow:\n" +
                sb.ToString(), ex
                ); // Add the original exception as the innerException
        }
    }
}

너는 천재 야 ...!
Florian F.

훌륭한 솔루션. 사람들은 투표하기 전에 모든 답변을 읽어야합니다.
Guilherme de Jesus Santos

3
또한 SaveChangesAsync 및 SaveChangesAsync (CancellationToken)도 재정의해야합니다. 최소한 모델 / DB에 대해서는 확실하지 않은 코드가 먼저 적용됩니다.
Carl

@jwize. 귀하의 답변은 데이터베이스 최초의 예외 처리 문제를 모델링하는 데 도움이되었습니다. 큰 답변
3355307

1
CodeFirst를 사용할 때 DbContext는 분명히 생성되지 않습니다. 그러나 디자이너를 사용하면 DbContext 및 Entity 클래스가 생성되며 부분 클래스를 사용하여 재정의해야합니다.
jwize

35

Richards 답변을 확장 방법으로 변환했습니다.

  public static int SaveChangesWithErrors(this DbContext context)
    {
        try
        {
            return context.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            StringBuilder sb = new StringBuilder();

            foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
                foreach (var error in failure.ValidationErrors)
                {
                    sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine();
                }
            }

            throw new DbEntityValidationException(
                "Entity Validation Failed - errors follow:\n" +
                sb.ToString(), ex
            ); // Add the original exception as the innerException
        }
    }

이런 식으로 전화하십시오 :

context.SaveChangesWithErrors();

4

craigvl의 버전을 C #으로 변환했는데 context.SaveChanges (); 다음과 같이 나를 위해 작동합니다.

try
{
    byte[] bytes = System.IO.File.ReadAllBytes(@"C:\Users\sheph_000\Desktop\Rawr.png");
    Console.WriteLine(bytes);

    context.BeverageTypes.AddOrUpdate(
        x => x.Name,
        new AATPos.DAL.Entities.BeverageType { ID = 1, Name = "Sodas" }
        );

    context.Beverages.AddOrUpdate(
        x => x.Name,
        new AATPos.DAL.Entities.Beverage { ID = 1, Name = "Coke", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 2, Name = "Fanta", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 3, Name = "Sprite", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 4, Name = "Cream Soda", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 5, Name = "Pepsi", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" }
        );

    context.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException ex)
{
    var sb = new System.Text.StringBuilder();
    foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation", failure.Entry.Entity.GetType());
        foreach (var error in failure.ValidationErrors)
                {
            sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
            sb.AppendLine();
                }
            }

    throw new Exception(sb.ToString());
}

3

아래의 올바른 경로를 찾아 주셔서 감사합니다. (같은 문제가 있음) 마이그레이션 구성 시드 방법에서 나에게 도움이되는 래퍼가없는 대안입니다.

 Protected Overrides Sub Seed(context As NotificationContext)

        Try
            context.System.AddOrUpdate(
               Function(c) c.SystemName,
                New E_NotificationSystem() With {.SystemName = "System1"},
                New E_NotificationSystem() With {.SystemName = "System2"},
                New E_NotificationSystem() With {.SystemName = "System3"})

            context.SaveChanges()

        Catch ex As DbEntityValidationException

            Dim sb As New StringBuilder

            For Each failure In ex.EntityValidationErrors

                sb.AppendFormat("{0} failed validation" & vbLf, failure.Entry.Entity.[GetType]())

                For Each [error] In failure.ValidationErrors
                    sb.AppendFormat("- {0} : {1}", [error].PropertyName, [error].ErrorMessage)
                    sb.AppendLine()
                Next
            Next

            Throw New Exception(sb.ToString())

        End Try
End Sub

그런 다음 패키지 관리자 콘솔에서 예외를 볼 수있었습니다. 이것이 누군가를 돕기를 바랍니다.


-1

I Also had same model validation problem but successfully catch by myself after lot of thinking;

I use reverse engineering method to catch the problem out of Over 80 + Model Classes;

1> Made copy of dbcontext, changing the name (I add "1" at end and make respective changes in class constructor and initialization etc.

Old:
 
>public class AppDb : IdentityDbContext<ApplicationUser>
>     
> {
> public AppDb(): base("DefaultConnection", throwIfV1Schema: false)
> {
> 
> }
>     
> public static AppDb Create()
>{
>return new AppDb();
>} 

**New:**

>public class AppDb1 : IdentityDbContext<ApplicationUser>
>{
>public AppDb1()
>: base("DefaultConnection", throwIfV1Schema: false)
>{
>}
> 
>public static AppDb1 Create()
> {
> return new AppDb1();
>  }`

...
2> Make changes to Codefirst Migration Configuration from Old DbContext to my new Context.

> internal sealed class Configuration :
> DbMigrationsConfiguration<DAL.AppDb1> { public Configuration() {
> AutomaticMigrationsEnabled = false; }    protected override void
> Seed(DAL.AppDb1 context) {`

3> Comment the Dbsets in new DbContext which was doubt.
4> Apply update migration if succeeded the probelm lye in Commented section.
5> if not then commented section is clear of bug clear.
6> repeat the (4) until found the right place of bug.
7> Happy Codding


1
텍스트가 코드 블록 안에 있지 않도록 코드를 포맷 할 때 좋습니다.
jmattheis

이것은 아마도 내가 본 최악의 포맷 유래의 답변입니다
crazy_crank
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.