La validation a échoué pour une ou plusieurs entités. Voir la propriété 'EntityValidationErrors' pour plus de détails

804

J'ai cette erreur lors de l'amorçage de ma base de données avec la première approche de code.

La validation a échoué pour une ou plusieurs entités. Voir la propriété 'EntityValidationErrors' pour plus de détails.

Pour être honnête, je ne sais pas comment vérifier le contenu des erreurs de validation. Visual Studio me montre que c'est un tableau avec 8 objets, donc 8 erreurs de validation.

Cela fonctionnait avec mon modèle précédent, mais j'ai apporté quelques modifications que j'explique ci-dessous:

  • J'avais une énumération appelée Status, je l'ai changé en une classe appelée Status
  • J'ai changé la classe ApplicantsPositionHistory pour avoir 2 clés étrangères vers la même table

Excusez-moi pour le code long, mais je dois tout coller. L'exception est levée dans la dernière ligne du code suivant.

namespace Data.Model
{  
    public class Position
    {
        [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]   
        public int PositionID { get; set; }

        [Required(ErrorMessage = "Position name is required.")]
        [StringLength(20, MinimumLength = 3, ErrorMessage = "Name should not be longer than 20 characters.")]
        [Display(Name = "Position name")]              
        public string name { get; set; }

        [Required(ErrorMessage = "Number of years is required")] 
        [Display(Name = "Number of years")]        
        public int yearsExperienceRequired { get; set; }

        public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }
    }

    public class Applicant
    {
        [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]      
        public int ApplicantID { get; set; }

        [Required(ErrorMessage = "Name is required")] 
        [StringLength(20, MinimumLength = 3, ErrorMessage="Name should not be longer than 20 characters.")]
        [Display(Name = "First and LastName")]
        public string name { get; set; }

        [Required(ErrorMessage = "Telephone number is required")] 
        [StringLength(10, MinimumLength = 3, ErrorMessage = "Telephone should not be longer than 20 characters.")]
        [Display(Name = "Telephone Number")]
        public string telephone { get; set; }

        [Required(ErrorMessage = "Skype username is required")] 
        [StringLength(10, MinimumLength = 3, ErrorMessage = "Skype user should not be longer than 20 characters.")]
        [Display(Name = "Skype Username")]
        public string skypeuser { get; set; }

        public byte[] photo { get; set; }

        public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }
    }

    public class ApplicantPosition
    {
        [Key]
        [Column("ApplicantID", Order = 0)]
        public int ApplicantID { get; set; }

        [Key]
        [Column("PositionID", Order = 1)]
        public int PositionID { get; set; }

        public virtual Position Position { get; set; }

        public virtual Applicant Applicant { get; set; }

        [Required(ErrorMessage = "Applied date is required")] 
        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        [Display(Name = "Date applied")]     
        public DateTime appliedDate { get; set; }

        [Column("StatusID", Order = 0)]
        public int StatusID { get; set; }

        public Status CurrentStatus { get; set; }

        //[NotMapped]
        //public int numberOfApplicantsApplied
        //{
        //    get
        //    {
        //        int query =
        //             (from ap in Position
        //              where ap.Status == (int)Status.Applied
        //              select ap
        //                  ).Count();
        //        return query;
        //    }
        //}
    }

    public class Address
    {
        [StringLength(20, MinimumLength = 3, ErrorMessage = "Country should not be longer than 20 characters.")]
        public string Country { get; set; }

        [StringLength(20, MinimumLength = 3, ErrorMessage = "City  should not be longer than 20 characters.")]
        public string City { get; set; }

        [StringLength(50, MinimumLength = 3, ErrorMessage = "Address  should not be longer than 50 characters.")]
        [Display(Name = "Address Line 1")]     
        public string AddressLine1 { get; set; }

        [Display(Name = "Address Line 2")]
        public string AddressLine2 { get; set; }   
    }

    public class ApplicationPositionHistory
    {
        [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
        public int ApplicationPositionHistoryID { get; set; }

        public ApplicantPosition applicantPosition { get; set; }

        [Column("oldStatusID")]
        public int oldStatusID { get; set; }

        [Column("newStatusID")]
        public int newStatusID { get; set; }

        public Status oldStatus { get; set; }

        public Status newStatus { get; set; }

        [StringLength(500, MinimumLength = 3, ErrorMessage = "Comments  should not be longer than 500 characters.")]
        [Display(Name = "Comments")]
        public string comments { get; set; }

        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        [Display(Name = "Date")]     
        public DateTime dateModified { get; set; }
    }

    public class Status
    {
        [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
        public int StatusID { get; set; }

        [StringLength(20, MinimumLength = 3, ErrorMessage = "Status  should not be longer than 20 characters.")]
        [Display(Name = "Status")]
        public string status { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.IO;

namespace Data.Model
{
    public class HRContextInitializer : DropCreateDatabaseAlways<HRContext>
    {
        protected override void Seed(HRContext context)
        {
            #region Status
            Status applied = new Status() { status = "Applied" };
            Status reviewedByHR = new Status() { status = "Reviewed By HR" };
            Status approvedByHR = new Status() { status = "Approved by HR" };
            Status rejectedByHR = new Status() { status = "Rejected by HR" };
            Status assignedToTechnicalDepartment = new Status() { status = "Assigned to Technical Department" };
            Status approvedByTechnicalDepartment = new Status() { status = "Approved by Technical Department" };
            Status rejectedByTechnicalDepartment = new Status() { status = "Rejected by Technical Department" };

            Status assignedToGeneralManager = new Status() { status = "Assigned to General Manager" };
            Status approvedByGeneralManager = new Status() { status = "Approved by General Manager" };
            Status rejectedByGeneralManager = new Status() { status = "Rejected by General Manager" };

            context.Status.Add(applied);
            context.Status.Add(reviewedByHR);
            context.Status.Add(approvedByHR);
            context.Status.Add(rejectedByHR);
            context.Status.Add(assignedToTechnicalDepartment);
            context.Status.Add(approvedByTechnicalDepartment);
            context.Status.Add(rejectedByTechnicalDepartment);
            context.Status.Add(assignedToGeneralManager);
            context.Status.Add(approvedByGeneralManager);
            context.Status.Add(rejectedByGeneralManager); 
            #endregion    

            #region Position
            Position netdeveloper = new Position() { name = ".net developer", yearsExperienceRequired = 5 };
            Position javadeveloper = new Position() { name = "java developer", yearsExperienceRequired = 5 };
            context.Positions.Add(netdeveloper);
            context.Positions.Add(javadeveloper); 
            #endregion

            #region Applicants
            Applicant luis = new Applicant()
            {
                name = "Luis",
                skypeuser = "le.valencia",
                telephone = "0491732825",
                photo = File.ReadAllBytes(@"C:\Users\LUIS.SIMBIOS\Documents\Visual Studio 2010\Projects\SlnHR\HRRazorForms\Content\pictures\1.jpg")
            };

            Applicant john = new Applicant()
            {
                name = "John",
                skypeuser = "jo.valencia",
                telephone = "3435343543",
                photo = File.ReadAllBytes(@"C:\Users\LUIS.SIMBIOS\Documents\Visual Studio 2010\Projects\SlnHR\HRRazorForms\Content\pictures\2.jpg")
            };

            context.Applicants.Add(luis);
            context.Applicants.Add(john); 
            #endregion

            #region ApplicantsPositions
            ApplicantPosition appicantposition = new ApplicantPosition()
            {
                Applicant = luis,
                Position = netdeveloper,
                appliedDate = DateTime.Today,
                StatusID = 1
            };

            ApplicantPosition appicantposition2 = new ApplicantPosition()
            {
                Applicant = john,
                Position = javadeveloper,
                appliedDate = DateTime.Today,
                StatusID = 1
            };        

            context.ApplicantsPositions.Add(appicantposition);            
            context.ApplicantsPositions.Add(appicantposition2); 
            #endregion

            context.SaveChanges(); --->> Error here
        }
    }
}
Luis Valencia
la source

Réponses:

1237

Pour être honnête, je ne sais pas comment vérifier le contenu des erreurs de validation. Visual Studio me montre que c'est un tableau avec 8 objets, donc 8 erreurs de validation.

En fait, vous devriez voir les erreurs si vous explorez ce tableau dans Visual studio pendant le débogage. Mais vous pouvez également intercepter l'exception, puis écrire les erreurs dans un magasin de journalisation ou la console:

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

EntityValidationErrorsest une collection qui représente les entités qui n'ont pas pu être validées avec succès, et la collection interne ValidationErrorspar entité est une liste d'erreurs au niveau de la propriété.

Ces messages de validation sont généralement suffisamment utiles pour trouver la source du problème.

Éditer

Quelques légères améliorations:

La valeur de la propriété incriminée peut être incluse dans la boucle interne comme suit:

        foreach (var ve in eve.ValidationErrors)
        {
            Console.WriteLine("- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",
                ve.PropertyName,
                eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName),
                ve.ErrorMessage);
        }

Bien que le débogage Debug.Writesoit préférable Console.WriteLinecar il fonctionne dans toutes sortes d'applications, pas seulement les applications console (merci à @Bart pour sa note dans les commentaires ci-dessous).

Pour les applications Web qui sont en production et qui utilisent Elmah pour la journalisation des exceptions, il s'est avéré très utile pour moi de créer une exception personnalisée et de l'écraser SaveChangesafin de lever cette nouvelle exception.

Le type d'exception personnalisé ressemble à ceci:

public class FormattedDbEntityValidationException : Exception
{
    public FormattedDbEntityValidationException(DbEntityValidationException innerException) :
        base(null, innerException)
    {
    }

    public override string Message
    {
        get
        {
            var innerException = InnerException as DbEntityValidationException;
            if (innerException != null)
            {
                StringBuilder sb = new StringBuilder();

                sb.AppendLine();
                sb.AppendLine();
                foreach (var eve in innerException.EntityValidationErrors)
                {
                    sb.AppendLine(string.Format("- Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                        eve.Entry.Entity.GetType().FullName, eve.Entry.State));
                    foreach (var ve in eve.ValidationErrors)
                    {
                        sb.AppendLine(string.Format("-- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",
                            ve.PropertyName,
                            eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName),
                            ve.ErrorMessage));
                    }
                }
                sb.AppendLine();

                return sb.ToString();
            }

            return base.Message;
        }
    }
}

Et SaveChangespeut être remplacé de la manière suivante:

public class MyContext : DbContext
{
    // ...

    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException e)
        {
            var newException = new FormattedDbEntityValidationException(e);
            throw newException;
        }
    }
}

Quelques remarques:

  • L'écran d'erreur jaune qu'Elmah affiche dans l'interface Web ou dans les e-mails envoyés (si vous l'avez configuré) affiche désormais les détails de validation directement en haut du message.

  • L'écrasement de la Messagepropriété dans l'exception personnalisée au lieu de l'écrasement ToString()présente l'avantage que le standard ASP.NET «Écran jaune de la mort (YSOD)» affiche également ce message. Contrairement à Elmah, le YSOD n'utilise apparemment pas ToString(), mais les deux affichent la Messagepropriété.

  • Envelopper l'original DbEntityValidationExceptioncomme exception interne garantit que la trace de la pile d'origine sera toujours disponible et s'affiche dans Elmah et YSOD.

  • En définissant un point d'arrêt sur la ligne, throw newException;vous pouvez simplement inspecter la newException.Messagepropriété sous forme de texte au lieu de forer dans les collections de validation, ce qui est un peu gênant et ne semble pas fonctionner facilement pour tout le monde (voir les commentaires ci-dessous).

Slauma
la source
87
L'exploration de l'exception ne fait rien. Il indique simplement qu'il existe un DbEntityValidationResult mais ne vous laisse pas vous développer !!
Shumii
30
@Shumii Voir cette réponse pour étendre l'exception.
Cavyn VonDeylen
18
Juste pour étendre une solution élégante. Vous pouvez remplacer la méthode savechanges dans votre propre classe DbContext, puis ajouter le bloc try catch, où le bloc try essaie simplement de sauvegarder (base.SaveChanges ()), et le bloc catch n'attrape que DbEntityValidationException. De cette façon, vous n'avez pas besoin de l'ajouter à chaque endroit où vous enregistrez vos modifications.
Milton
7
Cela a sauvé mon bacon à plus d'une occasion. Je n'ai pu voter qu'une seule fois. J'aurais aimé qu'ils me laissent voter pour chaque fois que j'ai copié et collé cela.
Damon Drake
5
+2 pour le code. En effet un sauveur :) -1 pour l'utilisation Console.WriteLine, j'estime que plus de gens écrivent des projets web que des applications console de nos jours, et Debug.Writetravaille dans les deux ...
Bart
459

Vous pouvez le faire à partir de Visual Studio pendant le débogage sans écrire de code, pas même un bloc catch.

Ajoutez simplement une montre avec le nom:

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

L'expression de surveillance $exceptionaffiche toute exception levée dans le contexte actuel, même si elle n'a pas été interceptée et affectée à une variable.

Basé sur http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/

yoel halb
la source
39
+1 Meilleure solution, et ne nécessite pas de modifications du code. Cool
Justas
4
+1 c'est tellement, très pratique! Vous n'avez même pas besoin d'avoir un bloc try / catch. Il suffit de coller ceci dans la liste de surveillance lorsque VS se casse et le tour est joué .. vous avez les erreurs de validation devant vous.
theyetiman
40
quelques fois par an, j'oublie comment faire et trouver cette réponse
Justin Moore
3
@zairja Je ne l'ai pas testé dans vb.net, mais il semble que la variable soit également définie pour vb.net dans msdn.microsoft.com/en-us/library/ms164891.aspx , mais la distribution n'est probablement pas défini pour vb.net, et à la place, vous devriez probablement faire DirectCast ($ exception, System.Data.Entity.Validation.DbEntityValidationException)
yoel halb
2
Je sais que les "merci" ne sont pas les bienvenus dans les commentaires mais pour m'éviter des heures de temps perdu ... merci!
Luther
105

Cela pourrait en fait le faire sans avoir à écrire du code:

Dans votre bloc catch, ajoutez un point d'arrêt à la ligne de code suivante:

catch (Exception exception)
{

}

Maintenant, si vous passez la souris sur exceptionou ajoutez-le à Watch, puis accédez aux détails de l'exception comme indiqué ci-dessous; vous verrez quelle (s) colonne (s) particulière (s) est / sont à l'origine du problème car cette erreur se produit généralement lorsqu'une contrainte de table est violée.

entrez la description de l'image ici

Grande image

t_plusplus
la source
4
Cette approche est très simple et profite de l'IDE :)
dsnunez
3
C'est une bonne solution car elle est rapide, simple, utilise l'IDE et m'a fait gagner une tonne de temps.
maxshuty
2
J'aime cette façon "Comment être un codeur et ne pas faire de code"
ouvert et gratuit
1
Je vous remercie. C'est simple mais c'est génial de voir l'exception en utilisant IDE.
Thomas.Benz
solution parfaite
Neeraj Singh Chouhan
46

Voici comment vous pouvez vérifier le contenu des EntityValidationErrors dans Visual Studio (sans écrire de code supplémentaire), c'est-à-dire pendant le débogage dans l' EDI .

Le problème?

Vous avez raison, le menu contextuel Afficher les détails du débogueur Visual Studio n'affiche pas les erreurs réelles dans la EntityValidationErrorscollection.

entrez la description de l'image ici

La solution!

Ajoutez simplement l'expression suivante dans une fenêtre Quick Watch et cliquez sur Réévaluer .

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

Dans mon cas, voyez comment je peux me développer à l' ValidationErrors Listintérieur de la EntityValidationErrorscollection

entrez la description de l'image ici

Références: article de blog mattrandle.me , réponse de @ yoel

Shiva
la source
3
pourquoi cela n'a pas été corrigé? cela devrait montrer l'erreur pas autre chose
Geomorillo
2
L'erreur de validation montre l'erreur de propriété, ex. le sujet est obligatoire, bonne réponse, merci
hamzeh.hanandeh
1
Génial! Ça m'a sauvé la nuit! :)
Patrick
1
c'est une façon intelligente de visualiser l'erreur exacte dans la montre ... merci!
Qwerty
39

Pour un moyen rapide de voir la première erreur sans même ajouter une montre, vous pouvez coller ceci dans la fenêtre immédiate:

((System.Data.Entity.Validation.DbEntityValidationException)$exception)
    .EntityValidationErrors.First()
    .ValidationErrors.First()
djdmbrwsk
la source
1
Vous pouvez également utiliser $ exception.EntityValidationErrors.SelectMany (x => x.ValidationErrors) .Select (x => x.ErrorMessage) pour les obtenir tous :) à mon humble avis en utilisant la fenêtre immédiate est la meilleure réponse
chrispepper1989
15

Pour tous ceux qui travaillent dans VB.NET

Try
Catch ex As DbEntityValidationException
    For Each a In ex.EntityValidationErrors
        For Each b In a.ValidationErrors
            Dim st1 As String = b.PropertyName
            Dim st2 As String = b.ErrorMessage
        Next
    Next
End Try
nghiavt
la source
12

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

ou:

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

Si vous n'êtes pas dans un try / catch ou n'avez pas accès à l'objet d'exception.

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

GONeale
la source
10

Si vous interceptez simplement une exception générique, il peut être avantageux de la convertir en exception DbEntityValidationException . Ce type d'exception possède une propriété Erreurs de validation, et en continuant à vous y développer, vous trouverez tous les problèmes.

Par exemple, si vous placez un point d'arrêt dans la prise, vous pouvez jeter les éléments suivants dans une montre:

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

Un exemple d'erreur est si un champ n'autorise pas les valeurs nulles et que vous avez une chaîne nulle, vous verrez qu'il indique que le champ est obligatoire.

Greg
la source
9

vérifiez simplement la longueur du champ de votre table de base de données. Votre texte d'entrée est supérieur à la longueur du type de données du champ de colonne

Hardeep Singh
la source
9

Dans le débogage, vous pouvez entrer cela dans votre champ de saisie d'évaluateur d'expression QuickWatch:

context.GetValidationErrors()
silverfox1948
la source
8

La réponse de @Slauma est vraiment géniale, mais j'ai trouvé que cela ne fonctionnait pas lorsqu'une propriété ComplexType n'était pas valide.

Par exemple, supposons que vous ayez une propriété Phonede type complexe PhoneNumber. Si la AreaCodepropriété n'est pas valide, le nom de la propriété dans ve.PropertyNamesest "Phone.AreaCode". Cela provoque l' eve.Entry.CurrentValues<object>(ve.PropertyName)échec de l'appel .

Pour résoudre ce problème, vous pouvez diviser le nom de la propriété à chaque fois ., puis réexaminer le tableau de noms de propriétés résultant. Enfin, lorsque vous arrivez en bas de chaîne, vous pouvez simplement restituer la valeur de la propriété.

Vous trouverez ci-dessous la FormattedDbEntityValidationExceptionclasse de @ Slauma avec prise en charge des ComplexTypes.

Prendre plaisir!

[Serializable]
public class FormattedDbEntityValidationException : Exception
{
    public FormattedDbEntityValidationException(DbEntityValidationException innerException) :
        base(null, innerException)
    {
    }

    public override string Message
    {
        get
        {
            var innerException = InnerException as DbEntityValidationException;
            if (innerException == null) return base.Message;

            var sb = new StringBuilder();

            sb.AppendLine();
            sb.AppendLine();
            foreach (var eve in innerException.EntityValidationErrors)
            {
                sb.AppendLine(string.Format("- Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                    eve.Entry.Entity.GetType().FullName, eve.Entry.State));
                foreach (var ve in eve.ValidationErrors)
                {
                    object value;
                    if (ve.PropertyName.Contains("."))
                    {
                        var propertyChain = ve.PropertyName.Split('.');
                        var complexProperty = eve.Entry.CurrentValues.GetValue<DbPropertyValues>(propertyChain.First());
                        value = GetComplexPropertyValue(complexProperty, propertyChain.Skip(1).ToArray());
                    }
                    else
                    {
                        value = eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName);
                    }
                    sb.AppendLine(string.Format("-- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",
                        ve.PropertyName,
                        value,
                        ve.ErrorMessage));
                }
            }
            sb.AppendLine();

            return sb.ToString();
        }
    }

    private static object GetComplexPropertyValue(DbPropertyValues propertyValues, string[] propertyChain)
    {
        var propertyName = propertyChain.First();
        return propertyChain.Count() == 1 
            ? propertyValues[propertyName] 
            : GetComplexPropertyValue((DbPropertyValues)propertyValues[propertyName], propertyChain.Skip(1).ToArray());
    }
}
mikesigs
la source
1
Je ne peux pas croire que plus de gens n'aient pas voté pour celui-ci, car c'est un scénario très réel et ça me rend fou les deux dernières nuits. Vous savez que le sentiment que vous ressentez lorsque vous réalisez que votre gestion des erreurs est ce qui déclenche réellement l'erreur? Pouah.
DJ Grossman
7

Notez que Entity.GetType().BaseType.Namedonne le nom de type que vous avez spécifié, pas celui avec tous les chiffres hexadécimaux dans son nom.

Eric Nelson
la source
7

Selon la réponse de @ Slauma et la suggestion de @ Milton, j'ai étendu la méthode de sauvegarde personnalisée de notre classe de base avec un try / catch qui gérera (et donc connectera notre journal des erreurs!) Ce genre d'exceptions.

// Where `BaseDB` is your Entities object... (it could be `this` in a different design)
public void Save(bool? validateEntities = null)
{
    try
    {
        //Capture and set the validation state if we decide to
        bool validateOnSaveEnabledStartState = BaseDB.Configuration.ValidateOnSaveEnabled;
        if (validateEntities.HasValue)
            BaseDB.Configuration.ValidateOnSaveEnabled = validateEntities.Value;

        BaseDB.SaveChanges();

        //Revert the validation state when done
        if (validateEntities.HasValue)
            BaseDB.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabledStartState;
    }
    catch (DbEntityValidationException e)
    {
        StringBuilder sb = new StringBuilder();
        foreach (var eve in e.EntityValidationErrors)
        {
            sb.AppendLine(string.Format("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)
            {
                sb.AppendLine(string.Format("- Property: \"{0}\", Error: \"{1}\"",
                                            ve.PropertyName,
                                            ve.ErrorMessage));
            }
        }
        throw new DbEntityValidationException(sb.ToString(), e);
    }
}
jocull
la source
1
Vous pouvez utiliser sb.AppendFormat () directement
Bastien Vandamme
1
Vous devrez également ajouter votre propre nouvelle ligne si vous utilisez AppendFormat.
jocull
7

J'ai dû écrire ceci dans la fenêtre Exécution: 3

(((exception as System.Data.Entity.Validation.DbEntityValidationException).EntityValidationErrors as System.Collections.Generic.List<System.Data.Entity.Validation.DbEntityValidationResult>)[0].ValidationErrors as System.Collections.Generic.List<System.Data.Entity.Validation.DbValidationError>)[0]

afin d'approfondir l'erreur exacte!

Nour Sabouny
la source
6

En utilisant la réponse de @Slauma, j'ai créé un extrait de code (un entourage avec extrait) pour une meilleure utilisation.

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>SurroundsWith</SnippetType>
      </SnippetTypes>
      <Title>ValidationErrorsTryCatch</Title>
      <Author>Phoenix</Author>
      <Description>
      </Description>
      <HelpUrl>
      </HelpUrl>
      <Shortcut>
      </Shortcut>
    </Header>
    <Snippet>
      <Code Language="csharp"><![CDATA[try
{
    $selected$ $end$
}
catch (System.Data.Entity.Validation.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;
}]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>
Phoenix_uy
la source
5

Attrapez l'exception dans une tentative de capture, puis une surveillance rapide ou ctrl + d & ctrl + q et vous pouvez explorer les EntityValidationErrors.

Brandon.Staley
la source
5

Je jette juste mes deux cents ...

Dans mon dbConfiguration.cs, j'aime encapsuler ma méthode context.SaveChanges () dans un try / catch et produire un fichier texte de sortie qui me permet de lire clairement les erreurs, et ce code les horodate également - pratique si vous rencontrer plus d'une erreur à des moments différents!

        try
        {
            context.SaveChanges();
        }
        catch (DbEntityValidationException e)
        {
            //Create empty list to capture Validation error(s)
            var outputLines = new List<string>();

            foreach (var eve in e.EntityValidationErrors)
            {
                outputLines.Add(
                    $"{DateTime.Now}: Entity of type \"{eve.Entry.Entity.GetType().Name}\" in state \"{eve.Entry.State}\" has the following validation errors:");
                outputLines.AddRange(eve.ValidationErrors.Select(ve =>
                    $"- Property: \"{ve.PropertyName}\", Error: \"{ve.ErrorMessage}\""));
            }
            //Write to external file
            File.AppendAllLines(@"c:\temp\dbErrors.txt", outputLines);
            throw;
        }
IfElseTryCatch
la source
5

Ce que j'ai trouvé ... quand j'ai eu l'erreur 'EntityValidationErrors' c'est que .... j'ai un champ dans ma base de données 'db1' dans la table 'tbladdress' comme 'address1' qui a une taille de 100 (ie adresse varchar (100) null) et je passais une valeur de plus de 100 caractères .. et cela conduisait à une erreur lors de l'enregistrement des données dans la base de données ....

Vous devez donc vérifier les données que vous transmettez sur le terrain.

Dharmendra Prajapati
la source
1
J'apprécie cette réponse car elle m'a réellement aidé à résoudre mon erreur. La table dans laquelle je sauvegardais dans ma base de données avait toutes les not nullcolonnes, donc une fois que j'ai ajouté des données à tous les éléments avant ma, db.SaveChanges()je n'ai reçu aucune erreur.
BinaryJoe01
3

Cela fonctionne pour moi.

var modelState = ModelState.Values;
if (!ModelState.IsValid)
{
    return RedirectToAction("Index", "Home", model);
}

Mettez un point d'arrêt sur l'instruction if. Ensuite, vous pouvez vérifier modelState dans les fenêtres de débogage. Sur chaque valeur, vous pouvez voir s'il y a une erreur et même le message d'erreur. C'est ça. Lorsque vous n'en avez plus besoin, supprimez ou commentez simplement la ligne.

J'espère que cela vous aidera.

Si demandé, je peux fournir une capture d'écran détaillée dans la fenêtre de débogage.

AngelDown
la source
3

Comme mentionné dans d'autres articles, interceptez simplement l'exception dans la classe DbEntityValidationException. Ce qui vous donnera l'eau dont vous avez besoin pendant les cas d'erreur.

 try
 {
  ....
 }
 catch(DbEntityValidationException ex)
 {
  ....
 }
Mayank
la source
2

J'ai fait face à cette erreur avant

quand j'ai essayé de mettre à jour un champ spécifique dans mon modèle dans le cadre de l'entité

Letter letter = new Letter {ID = letterId, ExportNumber = letterExportNumber,EntityState = EntityState.Modified};
LetterService.ChangeExportNumberfor(letter);
//----------


public int ChangeExportNumber(Letter letter)
    {
        int result = 0;
        using (var db = ((LettersGeneratorEntities) GetContext()))
        {
            db.Letters.Attach(letter);
            db.Entry(letter).Property(x => x.ExportNumber).IsModified = true;
            result += db.SaveChanges();
        }
        return result;
    }

et selon les réponses ci-dessus

J'ai trouvé le message de validation The SignerName field is required.

qui pointant vers le champ dans mon modèle

et quand j'ai vérifié mon schéma de base de données, j'ai trouvé

entrez la description de l'image ici

donc hors coure ValidationExceptiona le droit de soulever

et selon ce champ, je veux qu'il soit nul, (je ne sais pas comment je l'ai gâché)

donc j'ai changé ce champ pour autoriser Null, et par cela mon code ne me donnera plus cette erreur

donc cette erreur se produira peut-être si vous invalidez l'intégrité de vos données de votre base de données

Basheer AL-MOMANI
la source
1
La question de savoir si une exception doit être levée ou non n'est pas la question ici. Ensuite, vous coupez quelques coins ici. Lorsqu'un champ est requis dans le schéma de base de données, vous avez besoin de plus que cela pour avoir une valeur DbEntityValidationExceptionaugmentée.
Gert Arnold
2

Veuillez vérifier la valeur des champs que vous transmettez, sont valides et selon les champs de la base de données. Par exemple, le nombre de caractères transmis dans un champ particulier est inférieur aux caractères définis dans le champ de table de base de données.

arun tiwari
la source
1

Si vous utilisez IIS avec l' authentification Windows et Entity Framework , soyez prudent authorize.

J'ai essayé de POSTsans mon autorisation et cela n'a pas fonctionné, et obtenir cette erreur db.SaveChangesAsync();, alors que tous les autres verbes GETet DELETEtravaillaient.

Mais quand j'ai ajouté AuthorizeAttribute comme annotation, cela a fonctionné.

[Authorize]
public async Task<IHttpActionResult> Post(...){
....
}
Toodoo
la source
1

Voici une autre façon de le faire au lieu d'utiliser des boucles foreach pour regarder à l'intérieur d'EntityValidationErrors. Bien sûr, vous pouvez formater le message à votre guise:

try {
        // your code goes here...
    } 
catch (DbEntityValidationException ex) 
    {
        Console.Write($"Validation errors: {string.Join(Environment.NewLine, ex.EntityValidationErrors.SelectMany(vr => vr.ValidationErrors.Select(err => $"{err.PropertyName} - {err.ErrorMessage}")))}", ex);
        throw;
    }
Quantum_Joe
la source
1

Dans mon cas, c'était parce que la longueur du champ de la base de données est inférieure à la longueur du champ d'entrée.

table de base de données

create table user(
  Username nvarchar(5) not  null
);

Ma contribution

User newUser = new User()
{
   Username = "123456"
};

la valeur de Username lengthest 5 qui est lessthan6

... cela peut aider quelqu'un

Qwerty
la source
0

Vérifiez si vous avez des Not Nullcontraintes dans vos colonnes de table et si vous ne transmettez pas la valeur de cette colonne lors des opérations d'insertion / mise à jour. Cela provoque cette exception dans le cadre d'entité.

s Jagathish
la source
0

J'ai également rencontré le même problème. J'ai mis à jour mon .edmx à partir de la base de données après que l'exception a disparu.

HariChintha
la source
0

Cette erreur se produit principalement en raison de la taille du champ. VÉRIFIEZ toutes les tailles de champ dans une table de base de données.

Alexander Zaldostanov
la source
0

A également eu du mal avec cette erreur et sur la base du sujet ici et cette réponse a pu comprendre un extrait à copier / coller sans avoir besoin de comprendre ce qui doit être importé (excellent pour les débutants C #), code ci-dessous:

try
{
  context.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException ex)
{
  foreach (var entityValidationErrors in ex.EntityValidationErrors)
  {
    foreach (var validationError in entityValidationErrors.ValidationErrors)
    {
      System.Diagnostics.Debug.WriteLine("Property: " + validationError.PropertyName + " Error: " + validationError.ErrorMessage);
    }
  }
}
Daniel Danielecki
la source