DbEntityValidationException-Comment puis-je facilement dire ce qui a causé l'erreur?

j'ai un projet qui utilise le cadre D'entité. En appelant SaveChanges sur mon DbContext , j'obtiens l'exception suivante:

Système

.Données.Entité.Validation.DbEntityValidationException: Validation échoué à une ou plusieurs entités. Voir la propriété "EntityValidationErrors" pour plus de détails.

tout cela est très bien, mais je ne veux pas attacher un débogueur à chaque fois que cette exception se produit. Plus de plus de, dans les environnements de production, Je ne peux pas facilement fixer un débogueur, donc je dois aller très loin pour reproduire ces erreurs.

Comment puis-je voir les détails cachés dans le DbEntityValidationException ?

202
demandé sur Martin Devillers 2013-04-04 23:54:47

9 réponses

la solution la plus simple est de surcharger SaveChanges sur votre classe entities. Vous pouvez attraper le DbEntityValidationException , déballer les erreurs réelles et créer un nouveau DbEntityValidationException avec le message amélioré.

  1. créez une classe partielle à côté de votre quelque chose.Cadre.cs fichier.
  2. utilisez le code au bas de ce message.
  3. C'est ça. Votre mise en œuvre utilisera automatiquement les modifications de type SaveChanges sans aucun travail de remaniement.

votre message d'exception ressemblera maintenant à ceci:

Système

.Données.Entité.Validation.DbEntityValidationException: Validation échoué à une ou plusieurs entités. Voir la propriété "EntityValidationErrors" pour plus de détails. Les erreurs de validation sont: le champ PhoneNumber doit être un type de chaîne ou de tableau d'une longueur maximale de "12"; Champ nom est obligatoire.

vous pouvez laisser tomber les SaveChanges dépassées dans n'importe quelle classe qui hérite de DbContext :

public partial class SomethingSomethingEntities
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (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);
    
            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

le DbEntityValidationException contient également les entités qui ont causé les erreurs de validation. Ainsi, si vous avez besoin d'encore plus d'informations, vous pouvez modifier le code ci-dessus pour produire des informations sur ces entités.

Voir aussi: http://devillers.nl/improving-dbentityvalidationexception/

403
répondu Martin Devillers 2014-08-09 01:47:10

comme Martin l'a indiqué, il y a plus d'information dans le DbEntityValidationResult . J'ai trouvé utile d'obtenir à la fois mon nom de classe POCO et le nom de la propriété dans chaque message, et je voulais éviter d'avoir à écrire des attributs ErrorMessage personnalisés sur toutes mes étiquettes [Required] juste pour cela.

le tweak suivant au code de Martin s'est occupé de ces détails pour moi:

// Retrieve the error messages as a list of strings.
List<string> errorMessages = new List<string>();
foreach (DbEntityValidationResult validationResult in ex.EntityValidationErrors)
{
    string entityName = validationResult.Entry.Entity.GetType().Name;
    foreach (DbValidationError error in validationResult.ValidationErrors)
    {
        errorMessages.Add(entityName + "." + error.PropertyName + ": " + error.ErrorMessage);
    }
}
43
répondu Eric Hirst 2013-10-07 16:31:26

pour visualiser la collection EntityValidationErrors , ajouter l'expression Watch suivante à la fenêtre Watch.

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

j'utilise visual studio 2013

41
répondu Shehab Fawzy 2016-01-13 12:45:47

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

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

cela vous permettra de creuser dans l'arbre ValidationErrors . C'est le moyen le plus facile que j'ai trouvé pour avoir un aperçu instantané de ces erreurs.

pour les utilisateurs Visual 2012+ qui se soucient seulement de la première erreur et pourraient ne pas avoir un bloc catch , vous pouvez même faire:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
13
répondu GONeale 2016-03-14 23:26:35

pour trouver rapidement un message d'erreur significatif en inspectant l'erreur lors du débogage:

  • ajouter une montre rapide pour:

    ((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
    
  • Forez dans EntityValidationErrors like this:

    (élément de collection par exemple [0]) > ValidationErrors > (élément de collection par exemple [0]) > ErrorMessage

9
répondu Chris Halcrow 2016-10-20 00:21:54

en fait, il ne s'agit que du problème de validation, le FE validera d'abord les propriétés de l'entité avant d'apporter des modifications à la base de données. Donc, EF va vérifier si la valeur de la propriété est hors de portée, comme quand vous avez conçu la table. Table_Column_UserName est varchar (20). Mais, dans ce, vous avez entré une valeur qui dépasse 20. Ou, dans d'autres cas, si la colonne ne peut pas être Null. Ainsi, dans le processus de validation, vous devez définir une valeur pour la colonne not null, peu importe si vous allez faire le changement. Personnellement, J'aime la réponse de Leniel Macaferi. Il peut vous montrer le détail des questions de validation

5
répondu Calvin 2016-10-27 01:15:41

je pense que" les erreurs de validation réelles " peuvent contenir des informations sensibles, et cela pourrait être la raison pour laquelle Microsoft a choisi de les mettre à un autre endroit (propriétés). La solution indiquée ici est pratique, mais elle doit être prise avec prudence.

je préférerais créer une méthode d'extension. D'autres raisons à cela:

  • Garder l'original trace de la pile
  • Suivez ouvert/fermé principe (ie.: Je peux utiliser différents messages pour les différents types de journaux)
  • dans les environnements de production, il pourrait y avoir d'autres endroits (p. ex.: autre dbcontext) où une exception DbEntityValidationException pourrait être lancée.
3
répondu Luis Toapanta 2015-08-18 22:07:14

pour les fonctions Azure nous utilisons cette extension simple à Microsoft.Extension.Journalisation.ILogger

public static class LoggerExtensions
{
    public static void Error(this ILogger logger, string message, Exception exception)
    {
        if (exception is DbEntityValidationException dbException)
        {
            message += "\nValidation Errors: ";
            foreach (var error in dbException.EntityValidationErrors.SelectMany(entity => entity.ValidationErrors))
            {
                message += $"\n * Field name: {error.PropertyName}, Error message: {error.ErrorMessage}";
            }
        }

        logger.LogError(default(EventId), exception, message);
    }
}

et exemple d'utilisation:

try
{
    do something with request and EF
}
catch (Exception e)
{
    log.Error($"Failed to create customer due to an exception: {e.Message}", e);
    return await StringResponseUtil.CreateResponse(HttpStatusCode.InternalServerError, e.Message);
}
0
répondu Juri 2018-03-15 16:27:15

utilisez le bloc essayer dans votre code comme

try
{
    // Your code...
    // Could also be before try if you know the exception occurs in SaveChanges

    context.SaveChanges();
}
catch (DbEntityValidationException e)
{
    foreach (var eve in e.EntityValidationErrors)
    {
        Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
            eve.Entry.Entity.GetType().Name, eve.Entry.State);
        foreach (var ve in eve.ValidationErrors)
        {
            Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                ve.PropertyName, ve.ErrorMessage);
        }
    }
    throw;
}

Vous pouvez vérifier les détails ici

  1. http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/

  2. échec de la Validation pour une ou plusieurs entités. Voir "EntityValidationErrors" pour plus de détails

  3. http://blogs.infosupport.com/improving-dbentityvalidationexception/

-2
répondu Atta H. 2017-08-18 15:32:10