Die Validierung für eine oder mehrere Entitäten ist fehlgeschlagen. Weitere Informationen finden Sie unter der Eigenschaft 'EntityValidationErrors'

804

Ich habe diesen Fehler beim Seeding meiner Datenbank mit Code First Approach.

Die Validierung für eine oder mehrere Entitäten ist fehlgeschlagen. Weitere Informationen finden Sie unter der Eigenschaft 'EntityValidationErrors'.

Um ehrlich zu sein, weiß ich nicht, wie ich den Inhalt der Validierungsfehler überprüfen soll. Visual Studio zeigt mir, dass es sich um ein Array mit 8 Objekten handelt, also 8 Validierungsfehler.

Dies funktionierte mit meinem Vorgängermodell, aber ich habe einige Änderungen vorgenommen, die ich unten erläutere:

  • Ich hatte eine Aufzählung namens Status und habe sie in eine Klasse namens Status geändert
  • Ich habe die Klasse ApplicantsPositionHistory so geändert, dass 2 Fremdschlüssel für dieselbe Tabelle vorhanden sind

Entschuldigen Sie den langen Code, aber ich muss alles einfügen. Die Ausnahme wird in der letzten Zeile des folgenden Codes ausgelöst.

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
quelle

Antworten:

1237

Um ehrlich zu sein, weiß ich nicht, wie ich den Inhalt der Validierungsfehler überprüfen soll. Visual Studio zeigt mir, dass es sich um ein Array mit 8 Objekten handelt, also 8 Validierungsfehler.

Eigentlich sollten Sie die Fehler sehen, wenn Sie während des Debuggens in Visual Studio in dieses Array bohren. Sie können die Ausnahme aber auch abfangen und die Fehler dann in einen Protokollspeicher oder in die Konsole schreiben:

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

EntityValidationErrorsist eine Sammlung, die die Entitäten darstellt, die nicht erfolgreich validiert werden konnten, und die innere Sammlung ValidationErrorspro Entität ist eine Liste von Fehlern auf Eigenschaftsebene.

Diese Validierungsmeldungen sind normalerweise hilfreich genug, um die Ursache des Problems zu finden.

Bearbeiten

Ein paar kleine Verbesserungen:

Der Wert der beleidigenden Eigenschaft kann wie folgt in die innere Schleife aufgenommen werden:

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

Während das Debuggen Debug.Writemöglicherweise vorzuziehen ist, Console.WriteLineda es in allen Arten von Anwendungen funktioniert, nicht nur in Konsolenanwendungen (danke an @Bart für seinen Hinweis in den Kommentaren unten).

Für Webanwendungen, die in Produktion sind und Elmah für die Ausnahmeprotokollierung verwenden, hat es sich für mich als sehr nützlich erwiesen, eine benutzerdefinierte Ausnahme zu erstellen und zu überschreiben, SaveChangesum diese neue Ausnahme auszulösen .

Der benutzerdefinierte Ausnahmetyp sieht folgendermaßen aus:

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

Und SaveChangeskann folgendermaßen überschrieben werden:

public class MyContext : DbContext
{
    // ...

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

Einige Anmerkungen:

  • Der gelbe Fehlerbildschirm, den Elmah in der Weboberfläche oder in den gesendeten E-Mails anzeigt (falls Sie dies konfiguriert haben), zeigt jetzt die Validierungsdetails direkt oben in der Nachricht an.

  • Das Überschreiben der MessageEigenschaft in der benutzerdefinierten Ausnahme anstelle des Überschreibens ToString()hat den Vorteil, dass das Standard-ASP.NET "Yellow Screen of Death (YSOD)" diese Meldung ebenfalls anzeigt. Im Gegensatz zu Elmah verwendet der YSOD anscheinend nicht ToString(), aber beide zeigen die MessageEigenschaft an.

  • Durch das Umschließen des Originals DbEntityValidationExceptionals innere Ausnahme wird sichergestellt, dass der ursprüngliche Stack-Trace weiterhin verfügbar ist und in Elmah und YSOD angezeigt wird.

  • Durch Festlegen eines Haltepunkts in der Zeile können throw newException;Sie die newException.MessageEigenschaft einfach als Text untersuchen, anstatt in die Validierungssammlungen zu bohren. Dies ist etwas umständlich und scheint nicht für alle einfach zu funktionieren (siehe Kommentare unten).

Slauma
quelle
87
Das Bohren in die Ausnahme führt zu nichts. Es heißt nur, dass es ein DbEntityValidationResult gibt, aber Sie können es nicht erweitern !!
Shumii
30
@Shumii Siehe diese Antwort , um die Ausnahme zu erweitern.
Cavyn VonDeylen
18
Nur um eine elegante Lösung zu erweitern. Möglicherweise möchten Sie die savechanges-Methode in Ihrer eigenen DbContext-Klasse überschreiben und dann den try catch-Block hinzufügen, wobei der try-Block nur versucht zu speichern (base.SaveChanges ()) und der catch-Block nur die DbEntityValidationException abfängt. Auf diese Weise müssen Sie es nicht an jedem Ort hinzufügen, an dem Sie Ihre Änderungen speichern.
Milton
7
Dies hat meinen Speck mehr als einmal gerettet. Ich konnte nur einmal upvoten. Ich wünschte, sie würden mich für jedes Mal, wenn ich dies kopiert und eingefügt habe, positiv bewerten lassen.
Damon Drake
5
+2 für den Code. In der Tat ein Retter :) -1 für die Verwendung Console.WriteLine, ich schätze, dass heutzutage mehr Leute Webprojekte schreiben als Konsolen-Apps, und Debug.Writefunktioniert in beiden ...
Bart
459

Sie können dies in Visual Studio während des Debuggens tun, ohne Code zu schreiben, nicht einmal einen Catch-Block.

Fügen Sie einfach eine Uhr mit dem Namen hinzu:

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

Der Überwachungsausdruck $exceptionzeigt alle im aktuellen Kontext ausgelösten Ausnahmen an, auch wenn sie nicht abgefangen und einer Variablen zugewiesen wurden.

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

yoel halb
quelle
39
+1 Viel bessere Lösung und erfordert keine Änderungen am Code. Cool
Justas
4
+1 das ist so sehr, sehr praktisch! Sie müssen nicht einmal einen Try / Catch-Block haben. Stecke dies einfach in die Beobachtungsliste, wenn VS kaputt geht und voila .. du hast die Validierungsfehler vor dir.
Theyetiman
40
ein paar mal im Jahr vergesse ich, wie man das macht und finde diese Antwort
Justin Moore
3
@zairja Ich habe es nicht in vb.net getestet, aber es scheint, dass die Variable auch für vb.net in msdn.microsoft.com/en-us/library/ms164891.aspx definiert ist , die Besetzung jedoch wahrscheinlich nicht definiert für vb.net, und stattdessen sollten Sie wahrscheinlich DirectCast ausführen ($ exception, System.Data.Entity.Validation.DbEntityValidationException)
yoel halb
2
Ich weiß, dass "Danke" in Kommentaren nicht willkommen ist, aber um mir Stunden verschwendeter Zeit zu ersparen ... danke!
Luther
105

Dies könnte tatsächlich geschehen, ohne Code schreiben zu müssen:

Fügen Sie in Ihrem Catch-Block in der folgenden Codezeile einen Haltepunkt hinzu:

catch (Exception exception)
{

}

Wenn Sie nun mit der Maus darüber fahren exceptionoder es hinzufügen, Watchnavigieren Sie wie unten gezeigt zu den Ausnahmedetails. Sie werden sehen, welche bestimmten Spalten das Problem verursachen, da dieser Fehler normalerweise auftritt, wenn eine Tabelleneinschränkung verletzt wird.

Geben Sie hier die Bildbeschreibung ein

Großes Bild

t_plusplus
quelle
4
Dieser Ansatz ist sehr einfach und nutzt die IDE :)
dsnunez
3
Dies ist eine gute Lösung, da sie schnell und einfach ist, die IDE verwendet und mir eine Menge Zeit gespart hat.
Maxshuty
2
Ich mag diese Art und Weise "Wie man ein Codierer ist und keinen Code macht"
offen und kostenlos
1
Vielen Dank. Dies ist einfach, aber es ist fantastisch, die Ausnahme mithilfe der IDE anzuzeigen.
Thomas.Benz
perfekte Lösung
Neeraj Singh Chouhan
46

So können Sie den Inhalt der EntityValidationErrors in Visual Studio überprüfen (ohne zusätzlichen Code zu schreiben), dh während des Debuggens in der IDE .

Das Problem?

Sie haben Recht, das Popup " Details anzeigen" des Visual Studio-Debuggers zeigt nicht die tatsächlichen Fehler in der EntityValidationErrorsSammlung an.

Geben Sie hier die Bildbeschreibung ein

Die Lösung!

Fügen Sie einfach den folgenden Ausdruck in ein Quick Watch- Fenster ein und klicken Sie auf Neu bewerten .

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

Sehen Sie in meinem Fall, wie ich in das ValidationErrors ListInnere der EntityValidationErrorsSammlung expandieren kann

Geben Sie hier die Bildbeschreibung ein

Referenzen: mattrandle.me Blogpost , @ yoels Antwort

Shiva
quelle
3
Warum wurde dies nicht behoben? es sollte den Fehler nicht etwas anderes zeigen
Geomorillo
2
Der Validierungsfehler zeigt den Eigenschaftsfehler, z. Betreff Feld ist erforderlich, gute Antwort, Danke
hamzeh.hanandeh
1
Großartig! Es hat meine Nacht gerettet! :)
Patrick
1
Dies ist eine clevere Möglichkeit, den genauen Fehler in der Uhr zu visualisieren ... danke!
Qwerty
39

Um den ersten Fehler schnell zu sehen, ohne eine Uhr hinzuzufügen, können Sie diesen in das Sofortfenster einfügen:

((System.Data.Entity.Validation.DbEntityValidationException)$exception)
    .EntityValidationErrors.First()
    .ValidationErrors.First()
djdmbrwsk
quelle
1
Sie können auch $ exception.EntityValidationErrors.SelectMany (x => x.ValidationErrors) .Select (x => x.ErrorMessage) verwenden alle von ihnen :) imho mit dem sofortigen Fenster zu bekommen , ist die beste Antwort
chrispepper1989
15

Für alle, die in arbeiten 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
quelle
12

catch {...}Öffnen Sie im Debug-Modus innerhalb des Blocks das Fenster "QuickWatch" ( ctrl+ alt+ q) und fügen Sie es dort ein:

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

oder:

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

Wenn Sie sich nicht in einem Versuch / Fang befinden oder keinen Zugriff auf das Ausnahmeobjekt haben.

Auf diese Weise können Sie einen Drilldown in den ValidationErrorsBaum durchführen. Dies ist der einfachste Weg, um sofort einen Einblick in diese Fehler zu erhalten.

GONeale
quelle
10

Wenn Sie lediglich eine generische Ausnahme abfangen , kann es von Vorteil sein, diese als DbEntityValidationException umzuwandeln . Dieser Ausnahmetyp verfügt über eine Validierungsfehler-Eigenschaft. Wenn Sie Ihren Weg in diese Ausnahme erweitern, werden Sie alle Probleme finden.

Wenn Sie beispielsweise einen Haltepunkt in den Fang einfügen, können Sie Folgendes in eine Uhr werfen:

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

Ein Beispiel für einen Fehler ist, wenn ein Feld keine Nullen zulässt und Sie eine Nullzeichenfolge haben, wird angezeigt, dass das Feld erforderlich ist.

Greg
quelle
9

Überprüfen Sie einfach die Feldlänge Ihrer Datenbanktabelle. Ihr Eingabetext ist größer als die Länge des Spaltenfelddatentyps

Hardeep Singh
quelle
9

Beim Debuggen können Sie dies in Ihr Eingabefeld für den QuickWatch-Ausdrucksauswerter eingeben:

context.GetValidationErrors()
Silberfuchs1948
quelle
8

Die Antwort von @Slauma ist wirklich großartig, aber ich habe festgestellt, dass es nicht funktioniert hat, als eine ComplexType-Eigenschaft ungültig war.

Angenommen, Sie haben eine Eigenschaft Phonevom komplexen Typ PhoneNumber. Wenn die AreaCodeEigenschaft ungültig ist, lautet der Eigenschaftsname in ve.PropertyNames"Phone.AreaCode". Dies führt dazu, dass der Aufruf eve.Entry.CurrentValues<object>(ve.PropertyName)fehlschlägt.

Um dies zu beheben, können Sie den Eigenschaftsnamen jeweils .aufteilen und dann das resultierende Array von Eigenschaftsnamen durchgehen. Wenn Sie am Ende der Kette ankommen, können Sie einfach den Wert der Eigenschaft zurückgeben.

Unten finden Sie die FormattedDbEntityValidationExceptionKlasse von @ Slauma mit Unterstützung für ComplexTypes.

Genießen!

[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
quelle
1
Ich kann nicht glauben, dass mehr Leute dieses nicht positiv bewertet haben, da es ein sehr reales Szenario ist und mich in den letzten zwei Nächten verrückt gemacht hat. Sie wissen, dass das Gefühl, das Sie bekommen, wenn Sie feststellen, dass Ihre Fehlerbehandlung den Fehler tatsächlich auslöst? Pfui.
DJ Grossman
7

Beachten Sie, dass Entity.GetType().BaseType.Nameder von Ihnen angegebene Typname angegeben wird, nicht der mit allen hexadezimalen Ziffern im Namen.

Eric Nelson
quelle
7

Per @ Slaumas Antwort und @ Miltons Vorschlag habe ich die benutzerdefinierte Speichermethode unserer Basisklasse um einen Versuch / Fang erweitert, der diese Art von Ausnahmen behandelt (und daher unsere Fehlerprotokollierung anmeldet!).

// 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);
    }
}
scherz
quelle
1
Sie können sb.AppendFormat () direkt verwenden
Bastien Vandamme
1
Sie müssen auch Ihre eigene neue Zeile hinzufügen, wenn Sie AppendFormat verwenden.
Jocull
7

Ich musste dies in das Sofortfenster schreiben: 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]

um tief in den genauen Fehler zu kommen!

Nour Sabouny
quelle
6

Mit der Antwort von @Slauma habe ich ein Code-Snippet (ein Surround mit Snippet) zur besseren Verwendung erstellt.

<?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
quelle
5

Fangen Sie die Ausnahme in einem Try-Catch ab und beobachten Sie dann schnell oder Strg + D & Strg + Q, und Sie können einen Drilldown zu den EntityValidationErrors durchführen.

Brandon.Staley
quelle
5

Ich werfe nur meine zwei Cent rein ...

In meiner Datei dbConfiguration.cs möchte ich meine context.SaveChanges () -Methode in ein try / catch einbinden und eine Ausgabetextdatei erstellen, mit der ich die Fehler klar lesen kann, und dieser Code stempelt sie auch mit Zeitstempeln - praktisch, wenn Sie zu unterschiedlichen Zeiten auf mehr als einen Fehler stoßen!

        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
quelle
5

Was ich gefunden habe ... als ich den Fehler 'EntityValidationErrors' bekam, ist, dass ... ich ein Feld in meiner Datenbank 'db1' in der Tabelle 'tbladdress' als 'address1' habe, das die Größe 100 hat (dh Adresse varchar (100) null) und ich habe einen Wert von mehr als 100 Zeichen übergeben. Dies führte zu Fehlern beim Speichern der Daten in der Datenbank.

Sie müssen also die Daten überprüfen, die Sie an das Feld übergeben.

Dharmendra Prajapati
quelle
1
Ich schätze diese Antwort, weil sie mir tatsächlich geholfen hat, meinen Fehler zu beheben. Die Tabelle, in der ich in meiner not nullDatenbank gespeichert habe, enthielt alle Spalten. Nachdem ich also vor meinem Hinzufügen Daten zu allen Elementen hinzugefügt hatte, db.SaveChanges()erhielt ich keinen Fehler.
BinaryJoe01
3

Das funktioniert bei mir.

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

Setzen Sie einen Haltepunkt auf die if-Anweisung. Anschließend können Sie modelState in Debug-Fenstern überprüfen. Bei jedem Wert können Sie sehen, ob ein Fehler vorliegt, und sogar die Fehlermeldung. Das ist es. Wenn Sie es nicht mehr benötigen, löschen oder kommentieren Sie einfach die Zeile.

Ich hoffe das wird helfen.

Auf Nachfrage kann ich im Debug-Fenster einen detaillierten Screenshot bereitstellen.

AngelDown
quelle
3

Wie in anderen Beiträgen erwähnt, fangen Sie einfach die Ausnahme in der DbEntityValidationException-Klasse ab. So erhalten Sie alles, was Sie in Fehlerfällen benötigen.

 try
 {
  ....
 }
 catch(DbEntityValidationException ex)
 {
  ....
 }
Mayank
quelle
2

Ich war schon einmal mit diesem Fehler konfrontiert

als ich versuchte, ein bestimmtes Feld in meinem Modell in Entity Framwork zu aktualisieren

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

und gemäß den obigen Antworten

Ich habe die Validierungsnachricht gefunden The SignerName field is required.

welches auf Feld in meinem Modell zeigt

und als ich mein Datenbankschema überprüfte, fand ich

Geben Sie hier die Bildbeschreibung ein

Off Coure ValidationExceptionhat also das Recht zu erhöhen

und gemäß diesem Feld möchte ich, dass es nullbar ist (ich weiß nicht, wie ich es durcheinander gebracht habe)

Also habe ich dieses Feld geändert, um Null zuzulassen, und dadurch gibt mir mein Code diesen Fehler nicht mehr

Dieser Fehler tritt möglicherweise auf, wenn Sie die Datenintegrität Ihrer Datenbank ungültig machen

Basheer AL-MOMANI
quelle
1
Ob eine Ausnahme ausgelöst werden soll oder nicht, ist hier nicht der Punkt. Als nächstes schneiden Sie hier einige Ecken. Wenn im Datenbankschema ein Feld erforderlich ist, benötigen Sie mehr als das, um eine DbEntityValidationExceptionErhöhung zu erhalten.
Gert Arnold
2

Bitte überprüfen Sie den Feldwert, den Sie übergeben, der gültig ist und den Datenbankfeldern entspricht. Beispielsweise ist die Anzahl der in einem bestimmten Feld übergebenen Zeichen geringer als die im Feld für die Datenbanktabelle definierten Zeichen.

Arun Tiwari
quelle
1

Wenn Sie IIS mit Windows Authentification and Entity Framework verwenden , sollten Sie es vorsichtig verwendenauthorize .

Ich habe versucht, POSTohne Autorisierung und es hat nicht funktioniert, und diesen Fehler zu bekommen db.SaveChangesAsync();, während alle anderen Verben GETund DELETEfunktionierten.

Aber als ich AuthorizeAttribute als Anmerkung hinzufügte, funktionierte es.

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

Hier ist eine andere Möglichkeit, dies zu tun, anstatt foreach-Schleifen zum Durchsuchen von EntityValidationErrors zu verwenden. Natürlich können Sie die Nachricht nach Ihren Wünschen formatieren:

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
quelle
1

In meinem Fall lag es daran, dass die Länge des Datenbankfeldes geringer ist als die Länge des Eingabefeldes.

Datenbanktabelle

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

Mein Input

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

Der Wert für Username lengthist 5, was lessthan6 ist

... das kann jemandem helfen

Qwerty
quelle
0

Überprüfen Sie, ob Not NullIhre Tabellenspalten Einschränkungen aufweisen und der Wert für diese Spalte beim Einfügen / Aktualisieren nicht übergeben wird. Dies führt zu dieser Ausnahme im Entity Framework.

s Jagathish
quelle
0

Ich hatte auch das gleiche Problem. Ich habe meine .edmx aus der Datenbank aktualisiert, nachdem die Ausnahme verschwunden ist.

HariChintha
quelle
0

Dieser Fehler tritt hauptsächlich aufgrund der Feldgröße auf. Überprüfen Sie alle Feldgrößen in einer Datenbanktabelle.

Alexander Zaldostanov
quelle
0

Hatte auch mit diesem Fehler zu kämpfen und basierend auf dem Thema hier und diese Antwort war in der Lage, einen Ausschnitt zum Kopieren / Einfügen herauszufinden, ohne herausfinden zu müssen, was importiert werden muss (ausgezeichnet für C # -Einsteiger), Code unten:

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
quelle