Obteniendo el tipo de error exacto de DbValidationException

184

Tengo la situación en la que estoy inicializando mi modelo en DatabaseInitializer () para EF 4.1 y obtengo este error molesto. "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details."Entonces, voy a este EntityValidationErrors y hay un campo {System.Data.Entity.Validation.DbEntityValidationResult}que no me da ninguna información sobre qué campo no pudo inicializar . ¿Hay alguna manera de obtener más información sobre este error?

Para aclarar las cosas:

Sé cómo solucionar el problema de la longitud de la cadena. Lo que pregunto es cómo obtengo el nombre exacto del campo que está rompiendo el modelo.

Naz
fuente

Respuestas:

377

Mientras está en modo de depuración dentro del catch {...}bloque, abra la ventana "QuickWatch" ( ctrl+ alt+ q) y pegue allí:

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

Esto le permitirá profundizar en el ValidationErrorsárbol. Es la forma más fácil que he encontrado para obtener información instantánea sobre estos errores.

Para los usuarios de Visual 2012+ que solo se preocupan por el primer error y pueden no tener un catchbloqueo, incluso pueden hacer:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
GONeale
fuente
9
Esto es mejor que la otra respuesta :)
Doug
98
Si usted no tiene un bloque catch, se puede reemplazar excon $exceptiony obtener el mismo resultado.
Ecyrb
también asegúrese de reemplazar excon w / e your catch (Exception THIS)is
Eonasdan
@Ecyrb, gracias. ahorraste horas de googlear. Además, incluso si el recuento de errores de validación se muestra como 1, en realidad hay dos elementos en la matriz con dos errores.
matriz
3
Para aquellos que no hacen referencia a System.Linq y usan una ventana inmediata:System.Linq.Enumerable.ToList(System.Linq.Enumerable.ToList(((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors)[0].ValidationErrors)[0].ErrorMessage
jpsimard-nyx
124

¿Podrías probar esto en un bloque 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
fuente
11

La mejor solución en mi opinión, es manejar este tipo de errores de manera centralizada.

simplemente agregue este método a la DbContextclase 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);
    }
}

Esto sobrescribirá el SaveChanges()método de su contexto y obtendrá una lista separada por comas que contiene todos los errores de validación de la entidad.

Espero que esto sea útil.

Chtiwi Malek
fuente
4

Bueno, tuve el mismo problema. Mi modelo funcionó bien en EF CTP5, pero no se pudo compilar en 4.1 con el mismo error "" Error de validación para una o más entidades "cuando intenté inicializarlo. Descubrí que tenía propiedades:

public string Comment {get; set;}

Luego, en el método de inicialización en el inicializador anulado, tuve un comentario bastante largo (alrededor de 600 letras).

Creo que el punto es: en la FE 4.1 que tiene a las anotaciones de datos establecido explícitamente en algunos casos. Para mí, establecer:

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

ayudado. Es extraño ya que CTP5 no tuvo problemas con eso.

Wojciech Kotlinski
fuente
Bueno, lo que preguntaba es cómo obtengo el nombre exacto de la propiedad que está rompiendo el modelo. Sin embargo, logré superar el problema que usted mencionó usando [StringLength (Int32.MaxValue)] como un atributo de mi propiedad (como lo sugirió Ladislav Mrnka y hablé de ello en esta pregunta stackoverflow.com/questions/5346155/… ) Powodzenia! =)
Naz
Esto fue arrojado cuando agregué una nueva propiedad a mi modelo en 4.1. Funcionaba perfectamente en 4.1 antes. Extraño. Resuelto agregando anotaciones a todas las propiedades en el modelo.
Roberto Bonini
1

Me pareció útil crear un contenedor SaveChanges que haga que los EntityValidationErrors sean más legibles:

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

y luego cambié 'entity.SaveChanges ()' a 'SaveChanges (entidades)' en todo mi proyecto

hombre sonriente
fuente
0

Sé que es una vieja pregunta, pero aquí está mi respuesta:

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

y si usa el código primero, también puede globalizar sus mensajes de error usando múltiples archivos de recursos

Por ejemplo, tengo estos dos archivos de recursos separados, uno para error y otro para nombre de propiedad y los uso de la siguiente manera: ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

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 puede ver, he traducido completamente mis mensajes de error, incluidos los nombres de las propiedades, por lo que podría usarlos en el usuario más tarde, por ejemplo:

ingrese la descripción de la imagen aquí

NikiUsefi
fuente