Entity Framework를 사용하여 SQL Server 데이터베이스의 변경 사항을 저장하는 동안 하나 이상의 엔터티에 대한 유효성 검사에 실패했습니다
편집 내용을 데이터베이스에 저장하고 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'속성을 참조하십시오.]
당신은 모든 정보를 추출 할 수있는 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);
}
}
}
코드 변경이 필요하지 않습니다.
catch {...}
블록 내에서 디버그 모드에있는 동안 "QuickWatch"창 ( Ctrl+ Alt+ Q)을 열고 여기에 붙여 넣으십시오.
((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors
또는:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
try / catch에 없거나 예외 개체에 액세스 할 수없는 경우
그러면 ValidationErrors
트리 로 드릴 다운 할 수 있습니다 . 이 오류에 대한 즉각적인 통찰력을 얻는 가장 쉬운 방법입니다.
속성 이름이 같은 클래스가있는 경우 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);
}
}
}
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...
}
}
}
이 구현은 엔터티 예외를 세부 사항 텍스트로 예외로 랩핑합니다. 그것은 처리 DbEntityValidationException
, DbUpdateException
, datetime2
범위 오류 (MS SQL) 및 메시지에 잘못된 엔티티의 키 포함 (유용 때 savind 많은 기관 중 하나에서 SaveChanges
호출).
먼저 SaveChanges
DbContext 클래스에서 재정의하십시오 .
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);
}
}
이 코드는 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;
}
오늘이 오류가 발생하여 잠시 동안 해결할 수 없었지만 RequireAttribute
모델에 s를 추가 한 후 일부 개발 시드 데이터가 모든 필수 필드를 채우지 않는다는 것을 깨달았습니다 .
따라서 어떤 종류의 초기화 전략을 통해 데이터베이스를 업데이트하는 동안이 오류가 발생 DropCreateDatabaseIfModelChanges
하면 시드 데이터가 모델 데이터 유효성 검사 속성을 충족하고 만족시켜야합니다 .
나는 이것이 질문의 문제와 약간 다르다는 것을 알고 있지만 인기있는 질문이므로 나 자신과 같은 문제를 가진 다른 사람들의 대답에 조금 더 추가 할 것이라고 생각했습니다.
희망이 다른 사람들을 돕습니다 :)
모든 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()
메서드를 덮어 쓰고 모든 엔터티 유효성 검사 오류가 포함 된 쉼표로 구분 된 목록이 표시됩니다.
또한 오류를 발생시키는 대신 프로덕션 환경에서 오류를 기록하도록 개선 할 수 있습니다.
이것이 도움이되기를 바랍니다.
다음은 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;
나는 OnSaveChanges를 등록하고 이것을 가지고있는 예외를 좋아하지 않습니다.
var validationErrors = model.GetValidationErrors();
var h = validationErrors.SelectMany(x => x.ValidationErrors
.Select(f => "Entity: "
+(x.Entry.Entity)
+ " : " + f.PropertyName
+ "->" + f.ErrorMessage));
유효성 검사 오류가있는 엔터티를 저장하려고 할 때도이 오류가 발생합니다. 이를 일으키는 좋은 방법은 DB에 저장하기 전에 ModelState.IsValid를 확인하지 않는 것입니다.
DB 행에 nvarchar (50)이 있으면 50자를 초과하지 않아야합니다. 어리석은 실수이지만 그것을 알아내는 데 3 시간이 걸렸습니다.
이것은 sql에서와 같이 특정 열에 허용되는 최대 문자 수로 인해 하나의 필드에 다음 데이터 유형이있을 수 nvarchar(5)
있지만 사용자가 입력 한 문자 수가 지정된 수보다 많으므로 오류가 발생합니다.
데이터베이스를 업데이트하는 동안 며칠 전에 같은 문제가 발생했습니다. 필자의 경우 예외를 일으키는 코드에 제공되지 않은 유지 관리를 위해 추가 된 새로운 Null이 아닌 열이 거의 없었습니다. 해당 필드와 해당 필드에 제공된 값과 해결 된 값을 알아냅니다.
당신의 대답을위한 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
모델에 의해 채워지지 않은 Property로 인해 발생할 수 있습니다. 대신 Controller에 의해 채워집니다.이 오류가 발생할 수 있습니다. 이에 대한 해결책은 ModelState 유효성 검사를 적용하기 전에 속성을 할당하는 것입니다. 그리고이 두 번째 가정은입니다. 데이터베이스에 이미 데이터가 있고 데이터를 업데이트하려고하지만 가져 오는 중일 수 있습니다.
내 경우에는 내가 설정 한 데이터 유형이 varchar (200) 인 테이블 열 이름 경로가 있습니다 .nvarchar (max)로 업데이트 한 후 edmx에서 테이블을 삭제 한 다음 테이블을 다시 추가하면 제대로 작동합니다.
'Programing' 카테고리의 다른 글
iOS의 NSDictionary에서 JSON 문자열 생성 (0) | 2020.03.04 |
---|---|
Java에서 Double을 정수로 캐스트 (0) | 2020.03.04 |
사용자가 IE를 사용하고 있는지 확인 (0) | 2020.03.04 |
JSON 객체를 typescript 클래스로 캐스트하는 방법 (0) | 2020.03.04 |
유니 코드, UTF, ASCII, ANSI 형식 차이 (0) | 2020.03.04 |