Obtendo o tipo exato de erro em DbValidationException

184

Eu tenho a situação em que estou inicializando meu modelo no DatabaseInitializer () para EF 4.1 e recebo esse erro irritante. "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details."Então, eu vou para EntityValidationErrors e há um campo {System.Data.Entity.Validation.DbEntityValidationResult}que não fornece nenhuma informação sobre qual campo ele não pôde inicializar. . Existe uma maneira de obter mais informações sobre esse erro?

Para esclarecer as coisas:

Eu sei como corrigir o problema do comprimento da string. O que estou perguntando é como obtenho o nome exato do campo que está quebrando o modelo.

Naz
fonte

Respostas:

377

Enquanto você estiver no modo de depuração dentro do catch {...}bloco, abra a janela "QuickWatch" ( ctrl+ alt+ q) e cole nela:

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

Isso permitirá que você faça drill down na ValidationErrorsárvore. É a maneira mais fácil que eu encontrei de obter informações instantâneas sobre esses erros.

Para usuários do Visual 2012+ que se preocupam apenas com o primeiro erro e podem não ter um catchbloqueio, você pode até fazer:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
GONeale
fonte
9
Isto é melhor do que a outra resposta :)
Doug
98
Se você não tiver um bloco de captura, poderá substituir expor $exceptione obter o mesmo resultado.
Ecyrb
também certifique-se de substituir expor w / e seu catch (Exception THIS)é
Eonasdan
@Ecyrb, obrigado. você economizou horas pesquisando no Google. Além disso, mesmo que a contagem de erros de validação seja mostrada como 1, na verdade existem dois elementos na matriz com dois erros.
matriz
3
Para aqueles que não referenciando System.Linq e usando a janela imediata:System.Linq.Enumerable.ToList(System.Linq.Enumerable.ToList(((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors)[0].ValidationErrors)[0].ErrorMessage
jpsimard-nyx
124

Você poderia tentar isso em um bloco try / catch?

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);
        }
    }
}
Trent Scholl
fonte
11

A melhor solução, na minha opinião, é lidar com esse tipo de erro de maneira centralizada.

basta adicionar este método à DbContextclasse principal :

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

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

Espero que isso seja útil.

Chtiwi Malek
fonte
4

Bem, eu tive o mesmo problema. Meu modelo funcionou bem no EF CTP5, mas não conseguiu compilar no 4.1 com o mesmo erro "" Falha na validação de uma ou mais entidades "quando tentei inicializá-lo. Descobri que tinha propriedade:

public string Comment {get; set;}

Então, no método seed no inicializador substituído, eu tive um longo comentário (cerca de 600 letras).

Penso que o ponto é: no EF 4.1, é necessário definir anotações de dados explicitamente em alguns casos. Para mim, definindo:

[StringLength(4000)] 
public string Comment {get; set;}

ajudou. É estranho, já que o CTP5 não teve problemas com isso.

Wojciech Kotlinski
fonte
Bem, o que eu estava perguntando é como obtenho o nome exato da propriedade que está quebrando o modelo. No entanto, eu consegui superar o problema que você declarou usando [StringLength (Int32.MaxValue)] como um atributo para minha propriedade (como sugerido por Ladislav Mrnka e eu conversamos sobre isso nesta questão stackoverflow.com/questions/5346155/… ) Powodzenia! =)
Naz
Isso foi lançado quando adicionei uma nova propriedade ao meu modelo no 4.1. Estava funcionando perfeitamente em 4.1 antes. Esquisito. Resolvido adicionando anotação a todas as propriedades no modelo.
Roberto Bonini 22/03
1

Achei útil criar um wrapper SaveChanges que tornasse o EntityValidationErrors mais legível:

Public Sub SaveChanges(entities As Entities)

    Try
        entities.SaveChanges()

    Catch ex As DbEntityValidationException

        Dim msg As New StringBuilder
        msg.AppendLine(ex.Message)

        For Each vr As DbEntityValidationResult In ex.EntityValidationErrors
            For Each ve As DbValidationError In vr.ValidationErrors
                msg.AppendLine(String.Format("{0}: {1}", ve.PropertyName, ve.ErrorMessage))
            Next
        Next

        Throw New DbEntityValidationException(msg.ToString, ex.EntityValidationErrors, ex)

    End Try

End Sub

e depois alterei 'entity.SaveChanges ()' para 'SaveChanges (entity)' em todo o meu projeto

smirkingman
fonte
0

Eu sei que é uma pergunta antiga, mas aqui está a minha resposta:

catch (DbEntityValidationException ex)
   {
    String.Join("\n", ex.EntityValidationErrors
          .SelectMany(x => x.ValidationErrors)
          .Select(x => x.ErrorMessage)
          .ToArray());
   }

e se você usar o código primeiro, também poderá globalizar suas mensagens de erro usando vários arquivos de recursos

Por exemplo, eu tenho esses dois arquivos de recursos separados, um para erro e outro para o nome da propriedade e os uso da seguinte maneira: insira a descrição da imagem aqui insira a descrição da imagem aqui

public class Person 
    {
        [Required(ErrorMessageResourceName = "required",ErrorMessageResourceType =typeof(ErrorMessages))]
        [MaxLength(100,ErrorMessageResourceName = "maxLength", ErrorMessageResourceType = typeof(ErrorMessages))]
        [Display(Name = "FirstName",ResourceType = typeof(Properties))]
        public string FirstName { get; set; }
         }

Como você pode ver, traduzi completamente minhas mensagens de erro, incluindo os nomes das propriedades, para poder usá-las posteriormente no usuário, por exemplo:

insira a descrição da imagem aqui

NikiUsefi
fonte