Entity Framework를 사용하여 SQL Server 데이터베이스의 변경 사항을 저장하는 동안 하나 이상의 엔터티에 대한 유효성 검사에 실패했습니다


337

편집 내용을 데이터베이스에 저장하고 ASP.NET MVC 3 / C #에서 Entity FrameWork Code-First를 사용하고 있지만 오류가 발생합니다. 내 이벤트 클래스에는 DateTime 및 TimeSpan 데이터 유형이 있지만 데이터베이스에는 각각 Date 및 Time이 있습니다. 이것이 이유가 될 수 있습니까? 변경 사항을 데이터베이스에 저장하기 전에 코드에서 적절한 데이터 유형으로 캐스트하는 방법

public class Event
{
    public int EventId { get; set; }
    public int CategoryId { get; set; }
    public int PlaceId { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }
    public DateTime EventDate { get; set; }
    public TimeSpan StartTime { get; set; }
    public TimeSpan EndTime { get; set; }
    public string Description { get; set; }
    public string EventPlaceUrl { get; set; }
    public Category Category { get; set; }
    public Place Place { get; set; }
}

제어기의 메소드 >>>> storeDB.SaveChanges ()의 문제점;

// POST: /EventManager/Edit/386        
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    var theEvent = storeDB.Events.Find(id);

    if (TryUpdateModel(theEvent))
    {
        storeDB.SaveChanges();
        return RedirectToAction("Index");
    }
    else
    {
        ViewBag.Categories = storeDB.Categories.OrderBy(g => g.Name).ToList();
        ViewBag.Places = storeDB.Places.OrderBy(a => a.Name).ToList();
        return View(theEvent);
    }
}

public class EventCalendarEntities : DbContext
{
    public DbSet<Event> Events { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Place> Places { get; set; } 
}

SQL Server 2008 R2 데이터베이스 / T-SQL

EventDate (Datatype = date)  
StartTime (Datatype = time)  
EndTime (Datatype = time)  

HTTP 양식

EventDate (Datatype = DateTime) e.g. 4/8/2011 12:00:00 AM  
StartTime (Datatype = Timespan/time not sure) e.g. 08:30:00  
EndTime (Datatype = Timespan/time not sure) e.g. 09:00:00  

'/'응용 프로그램에 서버 오류가 있습니다.

하나 이상의 엔터티에 대한 유효성 검사에 실패했습니다. 자세한 내용은 'EntityValidationErrors'속성을 참조하십시오.

설명 : 현재 웹 요청을 실행하는 동안 처리되지 않은 예외가 발생했습니다. 오류 및 코드에서 발생한 위치에 대한 자세한 정보는 스택 추적을 검토하십시오.

예외 정보 : System.Data.Entity.Validation.DbEntityValidationException : 하나 이상의 엔터티에 대한 유효성 검사에 실패했습니다. 자세한 내용은 'EntityValidationErrors'속성을 참조하십시오.

소스 오류 :

Line 75:             if (TryUpdateModel(theEvent))
Line 76:             {
Line 77:                 storeDB.SaveChanges();
Line 78:                 return RedirectToAction("Index");
Line 79:             }

소스 파일 : C : \ sep \ MvcEventCalendar \ MvcEventCalendar \ Controllers \ EventManagerController.cs 줄 : 77

스택 추적 :

[DbEntityValidationException : 하나 이상의 엔티티에 대한 유효성 검증에 실패했습니다. 자세한 내용은 'EntityValidationErrors'속성을 참조하십시오.]


8
필수 필드 중 하나에 널값이있을 수 있습니다. EventDate, StartTime, Price, Category 등
Daveo

각각이 데이터베이스 정의 유형과 일치하는지 확인하기 위해 게시되는 양식 변수를 검사 했습니까? 또는 Daveo의 말처럼 필수 양식 값 중 하나가 누락되었습니다.
timothyclifford

게시 된 모든 양식 변수가 데이터베이스 정의 유형과 일치하지는 않습니다. 데이터베이스에서 날짜와 시간을 사용했지만 .NET에는 동등한 데이터 형식이 없습니다. 따라서 DateTime 및 TimeSpan을 사용했습니다. 이제 둘을 날짜와 시간으로 각각 변환해야합니다.
user522767

나에게 오류의 소스는 30 개 이상의 문자를 가지고 있으며, 데이터베이스 내 필드의 크기는 30이었다 문자열 필드했다
Mojtaba

답변:


840

당신은 모든 정보를 추출 할 수있는 DbEntityValidationException다음 코드 (: 당신이 네임 스페이스를 추가 할 필요가와를 System.Data.Entity.Validation하고 System.Diagnostics당신에 using목록) :

catch (DbEntityValidationException dbEx)
{
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
            Trace.TraceInformation("Property: {0} Error: {1}", 
                                    validationError.PropertyName, 
                                    validationError.ErrorMessage);
        }
    }
}

7
시드 데이터가 모델 속성 규칙 (과 같은 Required)을 완전히 만족하지 않는 경우에도이 오류가 발생할 수 있습니다 . 좀 더 많은 정보로 답변을 추가했습니다.
dan richardson

8
실제로 트레이스 출력을 볼 수있는 위치를 설명하면 대답을 개선 할 수 있습니다.
mkataja

1
나는이 발견 MSDN 기사 추적이 매우 유용 것에 대해
Borik의

2
당신은 인터넷을 이겼습니다.
Leandro

8
추적 출력은 출력 창에서 볼 수 있습니다. 상단-> Windows-> 출력
reggaeguitar

249

코드 변경이 필요하지 않습니다.

당신이 내 디버그 모드에있는 동안 catch {...}블록 "QuickWatch"창 ( Ctrl+ Alt+ Q)을 열고 여기에 붙여 넣으십시오.

((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors

또는:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors

try / catch에 없거나 예외 개체에 액세스 할 수없는 경우

그러면 ValidationErrors트리 로 드릴 다운 할 수 있습니다 . 이 오류에 대한 즉각적인 통찰력을 얻는 가장 쉬운 방법입니다.


6
당신은 내 친구가 천재입니다, 당신은 내가받은 ET 오류를 추적하는 데 도움을주었습니다. 감사합니다!
Mark Kram

4
문제 없습니다 :) 그러나 천재는 아닙니다.
QuickWatch를

4
예외 객체 / 변수에 액세스 할 수없는 사람들을 위해 답변을 업데이트했습니다.
GONeale

7
이 예외가 발생할 때마다 오류를 검색 한 다음 여기에옵니다 (Google의 두 번째 결과).이 게시물을 찾은 다음 디버그> 조사 식 패널에서 두 번째 솔루션을 사용합니다. 수십 번 했어. 고 넬레 감사합니다.
Ata S.

1
두 번째 쿼리를 실행할 때 "현재 컨텍스트에 '$ exception'이름이 없습니다"라는 유일한 사람입니까?
Alex Klaus

37

속성 이름이 같은 클래스가있는 경우 Praveen의 답변에 대한 작은 확장이 있습니다.

 catch (DbEntityValidationException dbEx)
 {
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
       foreach (var validationError in validationErrors.ValidationErrors)
       {
          Trace.TraceInformation(
                "Class: {0}, Property: {1}, Error: {2}",
                validationErrors.Entry.Entity.GetType().FullName,
                validationError.PropertyName,
                validationError.ErrorMessage);
       }
    }
 }

22

Praveen과 Tony의 개선으로 재정의를 사용합니다.

public partial class MyDatabaseEntities : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    Trace.TraceInformation("Class: {0}, Property: {1}, Error: {2}",
                        validationErrors.Entry.Entity.GetType().FullName,
                        validationError.PropertyName,
                        validationError.ErrorMessage);
                }
            }

            throw;  // You can also choose to handle the exception here...
        }
    }
}

6

이 구현은 엔터티 예외를 세부 사항 텍스트로 예외로 랩핑합니다. 그것은 처리 DbEntityValidationException, DbUpdateException, datetime2범위 오류 (MS SQL) 및 (메시지 하나에 유용 때 savind 많은 개체를 무효 엔티티의 키를 포함SaveChanges 호출).

먼저 SaveChangesDbContext 클래스에서 재정의하십시오 .

public class AppDbContext : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException dbEntityValidationException)
        {
            throw ExceptionHelper.CreateFromEntityValidation(dbEntityValidationException);
        }
        catch (DbUpdateException dbUpdateException)
        {
            throw ExceptionHelper.CreateFromDbUpdateException(dbUpdateException);
        }
    }   

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
    {
        try
        {
            return await base.SaveChangesAsync(cancellationToken);
        }
        catch (DbEntityValidationException dbEntityValidationException)
        {
            throw ExceptionHelper.CreateFromEntityValidation(dbEntityValidationException);
        }
        catch (DbUpdateException dbUpdateException)
        {
            throw ExceptionHelper.CreateFromDbUpdateException(dbUpdateException);
        }
    }

ExceptionHelper 클래스 :

public class ExceptionHelper
{
    public static Exception CreateFromEntityValidation(DbEntityValidationException ex)
    {
        return new Exception(GetDbEntityValidationMessage(ex), ex);
    }

    public static string GetDbEntityValidationMessage(DbEntityValidationException ex)
    {
        // Retrieve the error messages as a list of strings.
        var errorMessages = ex.EntityValidationErrors
            .SelectMany(x => x.ValidationErrors)
            .Select(x => x.ErrorMessage);

        // Join the list to a single string.
        var fullErrorMessage = string.Join("; ", errorMessages);

        // Combine the original exception message with the new one.
        var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
        return exceptionMessage;
    }

    public static IEnumerable<Exception> GetInners(Exception ex)
    {
        for (Exception e = ex; e != null; e = e.InnerException)
            yield return e;
    }

    public static Exception CreateFromDbUpdateException(DbUpdateException dbUpdateException)
    {
        var inner = GetInners(dbUpdateException).Last();
        string message = "";
        int i = 1;
        foreach (var entry in dbUpdateException.Entries)
        {
            var entry1 = entry;
            var obj = entry1.CurrentValues.ToObject();
            var type = obj.GetType();
            var propertyNames = entry1.CurrentValues.PropertyNames.Where(x => inner.Message.Contains(x)).ToList();
            // check MS SQL datetime2 error
            if (inner.Message.Contains("datetime2"))
            {
                var propertyNames2 = from x in type.GetProperties()
                                        where x.PropertyType == typeof(DateTime) ||
                                            x.PropertyType == typeof(DateTime?)
                                        select x.Name;
                propertyNames.AddRange(propertyNames2);
            }

            message += "Entry " + i++ + " " + type.Name + ": " + string.Join("; ", propertyNames.Select(x =>
                string.Format("'{0}' = '{1}'", x, entry1.CurrentValues[x])));
        }
        return new Exception(message, dbUpdateException);
    }
}

예외를 처리하려면 SaveChangesAsync 호출을 기다려야합니다.
Arnab Chakraborty

감사합니다, Arnab Chakraborty ! 답변 수정
Sel

5

이 코드는 Entity VAlidation Erros에 문제가있을 때 문제를 찾는 데 도움이되었습니다. 엔터티 정의에 대한 정확한 문제를 알려줍니다. storeDB.SaveChanges ()를 포함해야하는 다음 코드를 시도하십시오. 다음 try catch 블록에서.

  try
{
         if (TryUpdateModel(theEvent))
         {
             storeDB.SaveChanges();
             return RedirectToAction("Index");
         }
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
    Exception raise = dbEx;
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
            string message = string.Format("{0}:{1}", 
                validationErrors.Entry.Entity.ToString(),
                validationError.ErrorMessage);
            // raise a new exception nesting
            // the current instance as InnerException
            raise = new InvalidOperationException(message, raise);
        }
    }
    throw raise;
}

4

오늘이 오류가 발생하여 잠시 동안 해결할 수 없었지만 RequireAttribute모델에 s를 추가 한 후 일부 개발 시드 데이터가 모든 필수 필드를 채우지 않는다는 것을 깨달았습니다 .
따라서 어떤 종류의 초기화 전략을 통해 데이터베이스를 업데이트하는 동안이 오류가 발생 DropCreateDatabaseIfModelChanges하면 시드 데이터가 모델 데이터 유효성 검사 속성을 충족하고 충족시켜야합니다 .

나는 이것이 질문의 문제와 약간 다르다는 것을 알고 있지만 인기있는 질문이므로 나 자신과 같은 문제를 가진 다른 사람들의 대답에 조금 더 추가 할 것이라고 생각했습니다.
희망이 다른 사람들을 돕습니다 :)


4

모든 SaveChanges()작업에 try / catch를 추가 하는 것은 좋은 습관이 아니라고 생각하면 중앙 집중화하는 것이 좋습니다.

이 클래스를 기본 DbContext클래스에 추가하십시오 .

public override int SaveChanges()
{
    try
    {
        return base.SaveChanges();
    }
    catch (DbEntityValidationException ex)
    {
        string errorMessages = string.Join("; ", ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage));
        throw new DbEntityValidationException(errorMessages);
    }
}

컨텍스트의 SaveChanges()메서드를 덮어 쓰고 모든 엔터티 유효성 검사 오류가 포함 된 쉼표로 구분 된 목록이 표시됩니다.

또한 오류를 발생시키는 대신 프로덕션 환경에서 오류를 기록하도록 향상시킬 수 있습니다.

이것이 도움이되기를 바랍니다.


"DbContext 클래스"는 어디에서 찾을 수 있습니까? 나는이 모든 MVC 물건에 약간 새로운 것입니다. MVC 5와 Entity Framework 6을 사용하고 있습니다. 솔루션 탐색기에서 이름이 무엇인지 알지 못합니다.
JustJohn

@JustJohn 데이터베이스 모델 (클래스 파일)에 있습니다. 어디를 모르는 경우 DbContext프로젝트에 대해 키워드를 전체 검색 할 수 있습니다 .
Chtiwi Malek

1
저는이 접근법이 앱의 보편적 인 솔루션이기 때문에이 방법이 가장
좋으며

3

다음은 Tony의 확장에 대한 확장입니다 ... :-)

Entity Framework 4.x의 경우 어떤 엔터티 인스턴스 (DB 레코드)에 문제가 있는지 알 수 있도록 키 필드의 이름과 값을 얻으려면 다음을 추가 할 수 있습니다. 이를 통해 DbContext 객체에서보다 강력한 ObjectContext 클래스 멤버에 액세스 할 수 있습니다.

// Get the key field name & value.
// This assumes your DbContext object is "_context", and that it is a single part key.
var e = ((IObjectContextAdapter)_context).ObjectContext.ObjectStateManager.GetObjectStateEntry(validationErrors.Entry.Entity);
string key = e.EntityKey.EntityKeyValues[0].Key;
string val = e.EntityKey.EntityKeyValues[0].Value;

3

나는 OnSaveChanges를 등록하고 이것을 가지고있는 예외를 좋아하지 않습니다.

var validationErrors = model.GetValidationErrors();

var h = validationErrors.SelectMany(x => x.ValidationErrors
                                          .Select(f => "Entity: " 
                                                      +(x.Entry.Entity) 
                                                      + " : " + f.PropertyName 
                                                      + "->" + f.ErrorMessage));

"OnSaveChanges를 등록했습니다"라는 말의 의미는 무엇입니까?
야마모토 아키라

다른 상황과 동일한 상황에서 OnSaveChanges에 연결했지만 예외 단계에 도달하지 못했습니다. \
Mickey Perlstein

2

유효성 검사 오류가있는 엔터티를 저장하려고 할 때도이 오류가 발생합니다. 이를 일으키는 좋은 방법은 DB에 저장하기 전에 ModelState.IsValid를 확인하지 않는 것입니다.


2

DB 행에 nvarchar (50)이 있으면 50자를 초과하지 않아야합니다. 어리석은 실수이지만 그것을 알아내는 데 3 시간이 걸렸습니다.


1

이것은 sql에서와 같이 특정 열에 허용되는 최대 문자 수로 인해 하나의 필드에 다음 데이터 유형이있을 수 nvarchar(5)있지만 사용자가 입력 한 문자 수가 지정된 수보다 많으므로 오류가 발생합니다.


1

데이터베이스를 업데이트하는 동안 며칠 전에 같은 문제가 발생했습니다. 필자의 경우 예외를 일으키는 코드에 제공되지 않은 유지 관리를 위해 추가 된 새로운 Null이 아닌 열이 거의 없었습니다. 해당 필드와 해당 필드에 제공된 값과 해결 된 값을 알아냅니다.


0

당신의 대답을위한 Thnaks, 그것은 나를 많이 도와줍니다. Vb.Net의 코드로 Vb.Net의이 Bolt 코드

Try
   Return MyBase.SaveChanges()
Catch dbEx As Validation.DbEntityValidationException
   For Each [error] In From validationErrors In dbEx.EntityValidationErrors
                       From validationError In validationErrors.ValidationErrors
                       Select New With { .PropertyName = validationError.PropertyName,
                                         .ErrorMessage = validationError.ErrorMessage,
                                         .ClassFullName = validationErrors.Entry.Entity
                                                                    .GetType().FullName}

        Diagnostics.Trace.TraceInformation("Class: {0}, Property: {1}, Error: {2}",
                                           [error].ClassFullName,
                                           [error].PropertyName,
                                           [error].ErrorMessage)
   Next
   Throw
End Try

0

모델에 의해 채워지지 않은 Property로 인해 발생할 수 있습니다. 대신 Controller에 의해 채워집니다.이 오류가 발생할 수 있습니다. 이에 대한 해결책은 ModelState 유효성 검사를 적용하기 전에 속성을 할당하는 것입니다. 그리고이 두 번째 가정은입니다. 데이터베이스에 이미 데이터가 있고 데이터를 업데이트하려고하지만 가져 오는 중일 수 있습니다.


0

내 경우에는 내가 설정 한 데이터 유형이 varchar (200) 인 테이블 열 이름 경로가 있습니다 .nvarchar (max)로 업데이트 한 후 edmx에서 테이블을 삭제 한 다음 테이블을 다시 추가하면 제대로 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.