Obtenir le type d'erreur exact à partir de DbValidationException

186

J'ai la situation où j'initialise mon modèle dans DatabaseInitializer () pour EF 4.1 et j'obtiens cette erreur ennuyeuse "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details."Donc, je vais à cette EntityValidationErrors et il y a un champ {System.Data.Entity.Validation.DbEntityValidationResult}qui ne me donne aucune information sur le champ qu'il n'a pas pu initialiser . Existe-t-il un moyen d'obtenir plus d'informations sur cette erreur?

Pour clarifier les choses:

Je sais comment résoudre le problème de longueur de chaîne. Ce que je demande, c'est comment obtenir le nom de champ exact qui brise le modèle.

Naz
la source

Réponses:

379

Pendant que vous êtes en mode débogage dans le catch {...}bloc, ouvrez la fenêtre "QuickWatch" ( ctrl+ alt+ q) et collez-y:

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

Cela vous permettra de creuser dans l' ValidationErrorsarbre. C'est le moyen le plus simple que j'ai trouvé pour obtenir un aperçu instantané de ces erreurs.

Pour les utilisateurs de Visual 2012+ qui se soucient uniquement de la première erreur et peuvent ne pas avoir de catchblocage, vous pouvez même faire:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
GONeale
la source
9
C'est mieux que l'autre réponse :)
Doug
98
Si vous n'avez pas de bloc catch, vous pouvez le remplacer expar $exceptionet obtenir le même résultat.
Ecyrb
assurez-vous également de remplacer expar w / e votre catch (Exception THIS)est
Eonasdan
@Ecyrb, merci. vous avez économisé des heures de recherche sur Google. En outre, même si le nombre d'erreurs de validation est affiché comme 1, il y a en fait deux éléments dans le tableau avec deux erreurs.
matrice du
3
Pour ceux qui ne référencent pas System.Linq et utilisent la fenêtre immédiate:System.Linq.Enumerable.ToList(System.Linq.Enumerable.ToList(((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors)[0].ValidationErrors)[0].ErrorMessage
jpsimard-nyx
124

Vous pourriez essayer ceci dans un bloc 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
la source
11

La meilleure solution à mon avis est de gérer ce type d'erreurs de manière centralisée.

ajoutez simplement cette méthode à la DbContextclasse principale :

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

Cela écrasera la SaveChanges()méthode de votre contexte et vous obtiendrez une liste séparée par des virgules contenant toutes les erreurs de validation d'entité.

espérons que cela est utile.

Chtiwi Malek
la source
4

Eh bien, j'ai eu le même problème. Mon modèle fonctionnait bien dans EF CTP5, mais n'a pas réussi à intégrer la version 4.1 avec la même erreur "" La validation a échoué pour une ou plusieurs entités "lorsque j'ai essayé de l'initaliser. J'ai découvert que j'avais la propriété:

public string Comment {get; set;}

Ensuite, dans la méthode seed dans l'initialiseur surchargé, j'ai eu un commentaire assez long (environ 600 lettres).

Je pense que le point est le suivant: dans EF 4.1, vous devez définir explicitement des annotations de données dans certains cas. Pour moi, définir:

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

aidé. C'est bizarre car CTP5 n'a eu aucun problème avec ça.

Wojciech Kotlinski
la source
Eh bien, ce que je demandais, c'est comment obtenir le nom exact de la propriété qui brise le modèle. Cependant, j'ai réussi à surmonter le problème que vous avez indiqué en utilisant [StringLength (Int32.MaxValue)] comme attribut pour ma propriété (comme cela a été suggéré par Ladislav Mrnka et j'en ai parlé dans cette question stackoverflow.com/questions/5346155/… ) Powodzenia! =)
Naz
Cela a été lancé lorsque j'ai ajouté une nouvelle propriété à mon modèle dans la version 4.1. Fonctionnait parfaitement dans 4.1 avant. Bizarre. Résolu en ajoutant une annotation à toutes les propriétés du modèle.
Roberto Bonini
1

J'ai trouvé utile de créer un wrapper SaveChanges qui rend les EntityValidationErrors plus lisibles:

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

puis a changé 'entity.SaveChanges ()' en 'SaveChanges (entity)' dans tout mon projet

homme souriant
la source
0

Je sais que c'est une vieille question mais voici ma réponse:

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

et si vous utilisez d'abord le code, vous pouvez également globaliser vos messages d'erreur à l'aide de plusieurs fichiers de ressources

Par exemple, j'ai ces deux fichiers de ressources séparés, un pour l'erreur et un pour le nom de la propriété et je les utilise comme suit: entrez la description de l'image ici entrez la description de l'image ici

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

Comme vous pouvez le voir, j'ai complètement traduit mes messages d'erreur, y compris les noms de propriétés, afin que je puisse ensuite les utiliser dans l'utilisateur plus tard, par exemple:

entrez la description de l'image ici

NikiUsefi
la source