878 Stimmen

Die Validierung ist für eine oder mehrere Entitäten fehlgeschlagen. Siehe Eigenschaft 'EntityValidationErrors' für weitere Details

Ich habe diesen Fehler, wenn ich meine Datenbank mit dem ersten Code-Ansatz füttere.

Die Validierung ist für eine oder mehrere Entitäten fehlgeschlagen. Siehe Eigenschaft 'EntityValidationErrors' für weitere Details.

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

Dies funktionierte mit meinem vorherigen Modell, aber ich habe ein paar Änderungen vorgenommen, die ich weiter 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 sie 2 Fremdschlüssel für dieselbe Tabelle hat

Verzeihen Sie mir 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
        }
    }
}

1352voto

Slauma Punkte 171348

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

Eigentlich sollten Sie die Fehler sehen, wenn Sie in diesem Array in Visual Studio während der Fehlersuche bohren. Aber Sie können auch die Ausnahme abfangen und dann die Fehler in einen Protokollspeicher oder 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;
}

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

Diese Validierungsmeldungen sind in der Regel hilfreich genug, um die Ursache des Problems zu finden.

bearbeiten

Ein paar kleine Verbesserungen:

El Wert der beanstandeten 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 der Fehlersuche Debug.Write könnte vorzuziehen sein gegenüber Console.WriteLine da es in allen Arten von Anwendungen funktioniert, nicht nur in Konsolenanwendungen (Dank an @Bart für seinen Hinweis in den Kommentaren unten).

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

Der benutzerdefinierte Ausnahmetyp sieht wie folgt 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 SaveChanges kann auf folgende Weise überschrieben werden:

public class MyContext : DbContext
{
    // ...

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

Ein paar Bemerkungen:

  • Der gelbe Fehlerbildschirm, den Elmah in der Weboberfläche oder in den gesendeten E-Mails anzeigt (wenn Sie das konfiguriert haben), zeigt nun die Validierungsdetails direkt am Anfang der Nachricht an.

  • Überschreiben der Message Eigenschaft in der benutzerdefinierten Ausnahme, anstatt sie zu überschreiben ToString() hat den Vorteil, dass der standardmäßige ASP.NET "Yellow screen of death (YSOD)" diese Meldung ebenfalls anzeigt. Im Gegensatz zu Elmah verwendet der YSOD offenbar keine ToString() , aber beide zeigen die Message Eigentum.

  • Das Original verpacken DbEntityValidationException als innere Ausnahme stellt sicher, dass der ursprüngliche Stacktrace weiterhin verfügbar ist und in Elmah und YSOD angezeigt wird.

  • Durch Setzen eines Haltepunkts in der Zeile throw newException; können Sie einfach die newException.Message Eigenschaft als Text zu verwenden, anstatt die Validierungssammlungen zu durchforsten, was etwas umständlich ist und nicht für jeden leicht zu funktionieren scheint (siehe Kommentare unten).

497voto

yoel halb Punkte 11337

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

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

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

Der Ausdruck der Uhr $exception zeigt jede im aktuellen Kontext ausgelöste Ausnahme an, auch wenn sie noch nicht abgefangen und einer Variablen zugewiesen wurde.

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

118voto

t_plusplus Punkte 3819

Damit könnte man es tatsächlich schaffen, ohne Code schreiben zu müssen:

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

catch (Exception exception)
{

}

Wenn Sie nun mit dem Mauszeiger auf exception oder fügen Sie sie dem Watch und navigieren Sie dann zu den Ausnahmedetails, wie unten gezeigt; Sie werden sehen, welche bestimmte(n) Spalte(n) das Problem verursacht/verursachen, da dieser Fehler normalerweise auftritt, wenn eine Tabellenbeschränkung verletzt wird.

enter image description here

Großes Bild

59voto

Shiva Punkte 19502

So können Sie den Inhalt der Datei EntityValidationErrors in Visual Studio (ohne zusätzlichen Code zu schreiben), d.h. während Fehlersuche im IDE .

Das Problem?

Sie haben Recht, der Debugger von Visual Studio ist Details anzeigen Popup zeigt nicht die tatsächlichen Fehler innerhalb der EntityValidationErrors Sammlung .

enter image description here

Die Lösung!

Fügen Sie einfach den folgenden Ausdruck in eine Schnellsuche Fenster und klicken Sie auf Bewerten Sie neu. .

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

In meinem Fall sehen Sie, wie ich in der Lage bin, die ValidationErrors List innerhalb der EntityValidationErrors Sammlung

enter image description here

Referenzen: mattrandle.me Blogbeitrag , @yoel's Antwort

41voto

djdmbrwsk Punkte 572

Um den ersten Fehler schnell zu sehen, ohne eine Uhr hinzufügen zu müssen, können Sie dies in das Sofort-Fenster einfügen:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X