Falha na validação de uma ou mais entidades ao salvar alterações no Banco de Dados do SQL Server usando o Entity Framework

Eu quero salvar meu Edit to Database e estou usando Entity FrameWork Code-First no asp.net MVC 3 / C # mas estou recebendo erros. Na minha class Event, eu tenho tipos de dados DateTime e TimeSpan, mas no meu database, eu tenho Data e hora, respectivamente. Poderia ser este o motivo? Como posso transmitir para o tipo de dados apropriado no código antes de salvar as alterações no database.

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; } } 

Método no controller >>>> Problem at 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); } } 

com

 public class EventCalendarEntities : DbContext { public DbSet Events { get; set; } public DbSet Categories { get; set; } public DbSet Places { get; set; } } 

Banco de dados do SQL Server 2008 R2 / T-SQL

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

Formulário Http

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

Erro de Servidor na ‘/’ Aplicação.

A validação falhou para uma ou mais entidades. Veja a propriedade ‘EntityValidationErrors’ para mais detalhes.

Descrição: ocorreu uma exceção não tratada durante a execução da solicitação da web atual. Por favor, revise o rastreamento de pilha para obter mais informações sobre o erro e onde ele se originou no código.

Detalhes da exceção: System.Data.Entity.Validation.DbEntityValidationException: falha na validação de uma ou mais entidades. Veja a propriedade ‘EntityValidationErrors’ para mais detalhes.

Erro de origem:

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

Arquivo de origem: C: \ sep \ MvcEventCalendar \ MvcEventCalendar \ Controllers \ EventManagerController.cs Linha: 77

Rastreamento de pilha:

[DbEntityValidationException: falha na validação de uma ou mais entidades. Veja a propriedade ‘EntityValidationErrors’ para mais detalhes.]

Você pode extrair todas as informações do DbEntityValidationException com o seguinte código (você precisa adicionar os namespaces: System.Data.Entity.Validation e System.Diagnostics à sua lista 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); } } } 

Nenhuma alteração de código necessária:

Enquanto estiver no modo de debugging dentro do bloco catch {...} , abra a janela “QuickWatch” ( Ctrl + Alt + Q ) e cole lá:

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

ou:

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

Se você não estiver em um try / catch ou não tiver access ao object de exceção.

Isso permitirá que você faça uma pesquisa detalhada na tree ValidationErrors . É a maneira mais fácil que encontrei para obter insights instantâneos desses erros.

No caso de você ter aulas com os mesmos nomes de propriedade, aqui está uma pequena extensão da resposta de 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); } } } 

Como uma melhoria para Praveen e Tony, eu uso um override:

 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... } } } 

Esse código ajudou a encontrar meu problema quando tive problemas com meus erros de validação de entidade. Ele me disse o problema exato com a minha definição de entidade. Tente seguir o código onde você precisa cobrir storeDB.SaveChanges (); no seguinte tente pegar o bloco.

  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; } 

Esta exceção de entidade de envolvimento de implementação para exceção com texto de detalhe. Ele manipula os erros de intervalo DbEntityValidationException , DbUpdateException , datetime2 (MS SQL) e inclui a chave da entidade inválida na mensagem (útil ao salvar muitas entidades em uma chamada SaveChanges ).

Primeiro, substitua SaveChanges na class 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 SaveChangesAsync(CancellationToken cancellationToken) { try { return await base.SaveChangesAsync(cancellationToken); } catch (DbEntityValidationException dbEntityValidationException) { throw ExceptionHelper.CreateFromEntityValidation(dbEntityValidationException); } catch (DbUpdateException dbUpdateException) { throw ExceptionHelper.CreateFromDbUpdateException(dbUpdateException); } } 

Classe 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 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); } } 

Eu estava recebendo este erro hoje e não consegui resolvê-lo por um tempo, mas percebi que era depois de adicionar alguns RequireAttribute s aos meus modelos e que alguns dados iniciais de desenvolvimento não estavam preenchendo todos os campos obrigatórios.
Então, apenas uma nota que se você está recebendo este erro enquanto atualiza o database através de algum tipo de estratégia init como DropCreateDatabaseIfModelChanges então você tem que ter certeza que seus dados de sementes preenchem e satisfazem quaisquer atributos de validação de dados do modelo .

Eu sei que isso é um pouco diferente do problema na pergunta, mas é uma pergunta popular, então pensei em acrescentar um pouco mais à resposta para os outros que têm o mesmo problema que eu.
Espero que isso ajude os outros 🙂

Eu acho que adicionando try / catch para cada operação SaveChanges() não é uma boa prática, é melhor centralizar isso:

Adicione esta class à class principal 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); } } 

Isso sobrescreverá o método SaveChanges() do contexto e você receberá uma lista separada por vírgula contendo todos os erros de validação da entidade.

Isso também pode ser melhorado, para registrar erros no env de produção, em vez de apenas lançar um erro.

Espero que isso seja útil.

Aqui está uma extensão da extensão de Tony … 🙂

Para o Entity Framework 4.x, se você deseja obter o nome e o valor do campo-chave para saber qual instância da entidade (registro do database) tem o problema, adicione o seguinte. Isso fornece access aos membros da class ObjectContext mais poderosos do seu object DbContext.

 // 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; 

Eu não gosto de exceções eu registrei o OnSaveChanges e tenho isso

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

Este erro também acontece quando você tenta salvar uma entidade que possui erros de validação. Uma boa maneira de causar isso é esquecer de verificar ModelState.IsValid antes de salvar em seu database.

Certifique-se de que, se você tiver nvarchar (50) na linha DB, não tente inserir mais de 50 caracteres nela. Erro estúpido, mas levou-me 3 horas para descobrir isso.

Isso pode ser devido ao número máximo de caracteres permitidos para uma coluna específica, como no campo sql one pode ter o seguinte tipo de dados nvarchar(5) mas o número de caracteres inseridos do usuário é maior que o especificado, daí o erro.

Eu enfrentei o mesmo problema há alguns dias, enquanto atualizava o database. No meu caso, houve poucas novas colunas não anuláveis ​​adicionadas para manutenção que não foram fornecidas no código que está causando a exceção. Eu descubro esses campos e forneço valores para eles e é resolvido.

Thnaks por suas respostas, isso me ajuda muito. como código em Vb.Net, este código Bolt para Vb.Net

 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 

Isso pode ser causado por Propriedade que não é preenchida pelo modelo .. em vez disso, ele é preenchido pelo Controlador .. que pode causar esse erro .. solução para isso é atribuir a propriedade antes de aplicar validação ModelState. e esta segunda hipótese é. talvez você já tenha dados no database e tente atualizá-los, mas agora os recupere.