การตรวจสอบล้มเหลวสำหรับเอนทิตีอย่างน้อยหนึ่งรายการ ดูคุณสมบัติ 'EntityValidationErrors' สำหรับรายละเอียดเพิ่มเติม


804

ฉันมีข้อผิดพลาดนี้เมื่อทำการ seed ฐานข้อมูลด้วยรหัสแรก

การตรวจสอบล้มเหลวสำหรับเอนทิตีอย่างน้อยหนึ่งรายการ ดูคุณสมบัติ 'EntityValidationErrors' สำหรับรายละเอียดเพิ่มเติม

ความซื่อสัตย์ฉันไม่รู้วิธีตรวจสอบเนื้อหาของข้อผิดพลาดในการตรวจสอบความถูกต้อง Visual Studio แสดงให้ฉันเห็นว่ามันเป็นอาร์เรย์ที่มีวัตถุ 8 รายการดังนั้นจึงมีข้อผิดพลาดในการตรวจสอบ 8 ข้อ

นี่เป็นการทำงานกับรุ่นก่อนหน้าของฉัน แต่ฉันทำการเปลี่ยนแปลงเล็กน้อยที่ฉันอธิบายด้านล่าง:

  • ฉันมีสถานะเรียกว่าสถานะฉันเปลี่ยนเป็นชั้นที่เรียกว่าสถานะ
  • ฉันเปลี่ยนคลาสผู้สมัครตำแหน่งประวัติเพื่อให้มี 2 foreign key เป็นตารางเดียวกัน

ขอโทษทีฉันสำหรับรหัสยาว แต่ฉันต้องวางทั้งหมด ข้อยกเว้นจะถูกโยนในบรรทัดสุดท้ายของรหัสต่อไปนี้

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

คำตอบ:


1237

ความซื่อสัตย์ฉันไม่รู้วิธีตรวจสอบเนื้อหาของข้อผิดพลาดในการตรวจสอบความถูกต้อง Visual Studio แสดงให้ฉันเห็นว่ามันเป็นอาร์เรย์ที่มีวัตถุ 8 รายการดังนั้นจึงมีข้อผิดพลาดในการตรวจสอบ 8 ข้อ

ที่จริงแล้วคุณควรเห็นข้อผิดพลาดถ้าคุณเจาะเข้าไปในอาร์เรย์นั้นใน Visual Studio ในระหว่างการดีบัก แต่คุณสามารถตรวจจับข้อยกเว้นแล้วเขียนข้อผิดพลาดไปยังที่เก็บบันทึกหรือคอนโซล:

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เป็นคอลเล็กชันที่แสดงถึงเอนทิตีที่ไม่สามารถตรวจสอบได้สำเร็จและคอลเล็กชันภายในValidationErrorsต่อเอนทิตีเป็นรายการข้อผิดพลาดในระดับคุณสมบัติ

ข้อความตรวจสอบเหล่านี้มักจะมีประโยชน์มากพอที่จะค้นหาที่มาของปัญหา

แก้ไข

การปรับปรุงเล็กน้อยบางประการ:

คุ้มค่าของการกระทำผิดกฎหมายของสถานที่สามารถรวมอยู่ในวงภายในเช่นดังนั้น:

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

ในขณะที่การดีบั๊กDebug.Writeอาจจะใช้งานได้ดีกว่าConsole.WriteLineเพราะมันทำงานได้กับแอพพลิเคชั่นทุกประเภทไม่เพียง แต่แอพพลิเคชั่นคอนโซล (ขอบคุณ @Bart สำหรับบันทึกของเขาในความคิดเห็นด้านล่าง)

สำหรับเว็บแอปพลิเคชั่นที่กำลังใช้งานอยู่และที่ใช้Elmahสำหรับการบันทึกข้อยกเว้นมันมีประโยชน์มากสำหรับฉันในการสร้างข้อยกเว้นที่กำหนดเองและเขียนทับSaveChangesเพื่อที่จะทิ้งข้อยกเว้นใหม่นี้

ประเภทข้อยกเว้นที่กำหนดเองมีลักษณะดังนี้:

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

และSaveChangesสามารถเขียนทับด้วยวิธีต่อไปนี้:

public class MyContext : DbContext
{
    // ...

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

ข้อสังเกตบางประการ:

  • หน้าจอข้อผิดพลาดสีเหลืองที่ Elmah แสดงในเว็บอินเตอร์เฟสหรือในอีเมลที่ส่ง (ถ้าคุณกำหนดค่าไว้) จะแสดงรายละเอียดการตรวจสอบความถูกต้องที่ด้านบนของข้อความ

  • การเขียนทับMessageคุณสมบัติในข้อยกเว้นแบบกำหนดเองแทนที่จะเขียนทับToString()มีประโยชน์ที่ ASP.NET "Yellow screen of death (YSOD)" มาตรฐาน ASP.NET แสดงข้อความนี้เช่นกัน ตรงกันข้ามกับ Elmah YSOD เห็นได้ชัดว่าไม่ได้ใช้ToString()แต่ทั้งคู่แสดงMessageคุณสมบัติ

  • การห่อต้นฉบับDbEntityValidationExceptionเป็นข้อยกเว้นภายในทำให้แน่ใจว่าการติดตามสแต็กดั้งเดิมจะยังคงมีอยู่และแสดงใน Elmah และ YSOD

  • โดยการตั้งค่าเบรกพอยต์ในบรรทัดthrow newException;คุณสามารถตรวจสอบnewException.Messageคุณสมบัติเป็นข้อความแทนที่จะเจาะเข้าไปในคอลเลกชันการตรวจสอบซึ่งเป็นบิตที่น่าอึดอัดใจและดูเหมือนจะไม่ทำงานได้ง่ายสำหรับทุกคน (ดูความคิดเห็นด้านล่าง)


87
การเจาะเข้าไปในข้อยกเว้นไม่ได้ทำอะไรเลย มันเพิ่งบอกว่ามี DbEntityValidationResult แต่ไม่ยอมให้คุณขยาย !!
Shumii

30
@Shumii ดูคำตอบนี้เพื่อขยายข้อยกเว้น
Cavyn VonDeylen

18
เพียงเพื่อขยายโซลูชันที่หรูหรา คุณอาจต้องการแทนที่เมธอด savechanges ในคลาส DbContext ของคุณเองจากนั้นเพิ่มลอง catch catch block โดยที่ลองบล็อกเพิ่งพยายามบันทึก (base.SaveChanges ()) และ catch block จับเฉพาะ DbEntityValidationException ด้วยวิธีนี้คุณไม่จำเป็นต้องเพิ่มในทุกที่ที่คุณบันทึกการเปลี่ยนแปลง
มิลตัน

7
นี่ช่วยเบคอนของฉันมากกว่าหนึ่งครั้ง ฉันทำได้เพียงครั้งเดียวเท่านั้น หวังว่าพวกเขาจะให้ฉันโหวตขึ้นทุกครั้งที่ฉันคัดลอกและวางสิ่งนี้
Damon Drake

5
+2 สำหรับรหัส อันที่จริงผู้ช่วยชีวิต :) -1 สำหรับการใช้Console.WriteLineงานฉันคาดว่าจะมีคนกำลังเขียนโปรเจ็กต์ทางเว็บมากขึ้นจากนั้นใช้แอปคอนโซลในปัจจุบันและDebug.Writeทำงานได้ทั้ง ...
Bart

459

คุณสามารถทำได้จาก Visual Studio ในระหว่างการดีบักโดยไม่ต้องเขียนโค้ดใด ๆ แม้แต่บล็อก catch

เพียงเพิ่มนาฬิกาที่มีชื่อ:

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

นิพจน์การเฝ้าดู$exceptionแสดงข้อยกเว้นใด ๆ ที่เกิดขึ้นในบริบทปัจจุบันแม้ว่าจะไม่ได้ถูกจับและกำหนดให้กับตัวแปร

อ้างอิงจากhttp://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/


39
+1 วิธีแก้ปัญหาที่ดีกว่าและไม่ต้องการการเปลี่ยนแปลงรหัส Cool
Justas

4
+1 นี่มันช่างมีประโยชน์มาก! คุณไม่จำเป็นต้องมีบล็อก try / catch เพียงแค่ติดสิ่งนี้ในรายการเฝ้าดูเมื่อ VS หยุดพักและ voila .. คุณมีข้อผิดพลาดในการตรวจสอบความถูกต้องต่อหน้าคุณ
Theyetiman

40
สองสามครั้งต่อปีฉันลืมวิธีการทำเช่นนี้และหาคำตอบนี้
จัสตินมัวร์

3
@zairja ฉันยังไม่ได้ทดสอบใน vb.net แต่ปรากฏว่าตัวแปรนั้นถูกกำหนดไว้สำหรับ vb.net เช่นกันในmsdn.microsoft.com/en-us/library/ms164891.aspxแต่ผู้ส่งอาจไม่ได้ กำหนดไว้สำหรับ vb.net และคุณควรทำ DirectCast แทน ($ exception, System.Data.Entity.Validation.DbEntityValidationException)
yoel halb

2
ฉันรู้ว่า "ขอบคุณ" ไม่ได้ยินดีต้อนรับในความคิดเห็น แต่เพื่อป้องกันไม่ให้ฉันชั่วโมงเสียเวลา ... ขอบคุณ!
ลูเธอร์

105

สิ่งนี้สามารถทำได้โดยไม่ต้องเขียนโค้ด:

ใน catch catch ของคุณเพิ่มจุดพักที่บรรทัดโค้ดต่อไปนี้:

catch (Exception exception)
{

}

ตอนนี้ถ้าคุณวางบนexceptionหรือเพิ่มลงในWatchจากนั้นนำทางไปยังรายละเอียดข้อยกเว้นดังที่แสดงด้านล่าง คุณจะเห็นว่าคอลัมน์ใดที่ทำให้เกิดปัญหาเนื่องจากข้อผิดพลาดนี้มักเกิดขึ้นเมื่อมีการละเมิดข้อ จำกัด ของตาราง

ป้อนคำอธิบายรูปภาพที่นี่

ภาพใหญ่


4
วิธีนี้เป็นวิธีที่ง่ายมากและใช้ประโยชน์จาก IDE :)
dsnunez

3
นี่เป็นทางออกที่ดีเพราะรวดเร็วง่ายใช้ประโยชน์จาก IDE และประหยัดเวลาได้มาก
maxshuty

2
ฉันชอบวิธีนี้ "ทำอย่างไรจึงจะเป็น coder และไม่ต้องทำโค้ด"
เปิดและฟรี

1
ขอบคุณ. มันง่าย แต่ก็ยอดเยี่ยมที่จะดูข้อยกเว้นโดยใช้ IDE
Thomas.Benz

โซลูชั่นที่สมบูรณ์แบบ
Neeraj Singh Chouhan

46

นี่คือวิธีที่คุณสามารถตรวจสอบเนื้อหาของEntityValidationErrorsใน Visual Studio (โดยไม่ต้องเขียนโค้ดพิเศษใด ๆ ) เช่นระหว่างการดีบักในIDE IDE

ปัญหา?

คุณถูกต้องป๊อปอัพรายละเอียดการดีบักเกอร์ของ Visual Studio ไม่แสดงข้อผิดพลาดจริงภายในEntityValidationErrorsคอลเลกชัน

ป้อนคำอธิบายรูปภาพที่นี่

การแก้ไขปัญหา!

เพียงเพิ่มนิพจน์ต่อไปนี้ในหน้าต่างดูด่วนและคลิกประเมินใหม่

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

ในกรณีของฉันดูว่าฉันสามารถขยายเข้าไปValidationErrors Listข้างในEntityValidationErrorsคอลเลกชันได้อย่างไร

ป้อนคำอธิบายรูปภาพที่นี่

: อ้างอิง mattrandle.me บล็อกโพสต์ , คำตอบ @ เยลของ


3
ทำไมสิ่งนี้ไม่ได้รับการแก้ไข? มันควรแสดงข้อผิดพลาดไม่ใช่อย่างอื่น
Geomorillo

2
ข้อผิดพลาดในการตรวจสอบความถูกต้องแสดงข้อผิดพลาดคุณสมบัติเช่น ต้อง
กรอก

1
ที่ดี! มันช่วยคืนฉันได้! :)
Patrick

1
นี่เป็นวิธีที่ชาญฉลาดในการมองเห็นข้อผิดพลาดที่แน่นอนในนาฬิกา ... ขอบคุณ!
Qwerty

39

สำหรับวิธีที่รวดเร็วในการดูข้อผิดพลาดแรกโดยไม่ต้องเพิ่มนาฬิกาคุณสามารถวางสิ่งนี้ในหน้าต่างทันที:

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

1
นอกจากนี้คุณยังสามารถใช้ $ exception.EntityValidationErrors.SelectMany (x => x.ValidationErrors) .Select (x => x.ErrorMessage) เพื่อรับทั้งหมด :) imho โดยใช้หน้าต่างทันทีเป็นคำตอบที่ดีที่สุด
chrispepper1989

15

สำหรับทุกคนที่ทำงานค่ะ 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

12

ในขณะที่คุณอยู่ในโหมดแก้ไขข้อบกพร่องภายในcatch {...}บล็อกเปิดหน้าต่าง "QuickWatch" ( ctrl+ alt+ q) และวางใน:

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

หรือ:

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

หากคุณไม่ได้ลอง / จับหรือไม่มีสิทธิ์เข้าถึงวัตถุยกเว้น

นี้จะช่วยให้คุณสามารถเจาะลึกลงไปในValidationErrorsต้นไม้ มันเป็นวิธีที่ง่ายที่สุดที่ฉันพบว่าได้รับข้อมูลเชิงลึกเกี่ยวกับข้อผิดพลาดเหล่านี้ทันที


10

หากคุณเพียงแค่จับข้อยกเว้นทั่วไปอาจเป็นประโยชน์กับคุณในการแปลงเป็นDbEntityValidationException DbEntityValidationExceptionข้อยกเว้นประเภทนี้มีคุณสมบัติข้อผิดพลาดในการตรวจสอบความถูกต้องและจะขยายวิธีการของคุณต่อไปคุณจะพบปัญหาทั้งหมด

ตัวอย่างเช่นหากคุณใส่จุดพักในการจับคุณสามารถโยนสิ่งต่อไปนี้ลงในนาฬิกา:

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

ตัวอย่างของข้อผิดพลาดคือถ้าเขตข้อมูลไม่อนุญาตให้มีค่า Null และคุณมีสตริง Null คุณจะเห็นว่ามีความจำเป็นต้องระบุเขตข้อมูล


9

เพียงตรวจสอบความยาวของฟิลด์ตารางฐานข้อมูลของคุณ ข้อความอินพุตของคุณมากกว่าความยาวของความยาวประเภทข้อมูลคอลัมน์


9

ในการดีบักคุณสามารถป้อนสิ่งนี้ในช่องป้อนข้อมูลนิพจน์ตัวประเมินนิพจน์ของคุณ:

context.GetValidationErrors()

8

คำตอบจาก @Slauma นั้นยอดเยี่ยมจริงๆ แต่ฉันพบว่ามันไม่ทำงานเมื่อคุณสมบัติ ComplexType ไม่ถูกต้อง

ตัวอย่างเช่นสมมติว่าคุณมีคุณสมบัติของชนิดที่ซับซ้อนPhone PhoneNumberหากAreaCodeคุณสมบัติไม่ถูกต้องชื่อคุณสมบัติในve.PropertyNamesนั้นคือ "Phone.AreaCode" สิ่งนี้ทำให้การเรียกeve.Entry.CurrentValues<object>(ve.PropertyName)ล้มเหลว

ในการแก้ไขปัญหานี้คุณสามารถแยกชื่อคุณสมบัติได้ในแต่ละชื่อ .จากนั้นเรียกคืนผ่านอาร์เรย์ผลลัพธ์ของชื่อคุณสมบัติ ในที่สุดเมื่อคุณมาถึงที่ด้านล่างของห่วงโซ่คุณก็สามารถคืนค่าของทรัพย์สิน

ด้านล่างคือ @ Slauma's FormattedDbEntityValidationExceptionคลาสพร้อมการสนับสนุน ComplexTypes

สนุก!

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

1
ฉันไม่อยากจะเชื่อว่ามีคนอีกจำนวนมากที่ไม่ได้ลงมือสนับสนุนเพราะมันเป็นสถานการณ์จริงและมันทำให้ฉันรู้สึกแย่เมื่อสองคืนที่ผ่านมา คุณรู้ว่าคุณรู้สึกว่าได้รับเมื่อคุณตระหนักถึงการจัดการข้อผิดพลาดของคุณคือสิ่งที่โยนข้อผิดพลาดจริงหรือไม่ ฮึ.
DJ Grossman

7

โปรดทราบว่าEntity.GetType().BaseType.Nameให้ชื่อประเภทที่คุณระบุไม่ใช่ชื่อที่มีเลขฐานสิบหกทั้งหมดในชื่อ


7

คำตอบต่อ @ Slauma และข้อเสนอแนะของ @ Milton ฉันได้ขยายวิธีการบันทึกที่กำหนดเองของคลาสพื้นฐานของเราด้วยการลอง / จับที่จะจัดการ

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

1
คุณสามารถใช้ sb.AppendFormat () โดยตรง
Bastien Vandamme

1
คุณจะต้องเพิ่มบรรทัดใหม่ของคุณเองเช่นกันหากคุณใช้ AppendFormat
jocull

7

ฉันต้องเขียนสิ่งนี้ในหน้าต่าง Immediate: 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]

เพื่อที่จะเข้าใจถึงข้อผิดพลาดที่แน่นอน!


6

การใช้คำตอบของ @Slauma ฉันได้สร้างโค้ดขนาดเล็ก (ล้อมรอบด้วยข้อมูลโค้ด) เพื่อการใช้งานที่ดีขึ้น

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

5

ตรวจสอบข้อยกเว้นในการลองจับแล้วดูอย่างรวดเร็วหรือ ctrl + d & ctrl + q และคุณสามารถเจาะลึกลงไปที่ EntityValidationErrors


5

เพียงแค่โยนสองเซ็นต์ของฉันใน ...

ภายใน dbConfiguration.cs ของฉันฉันชอบที่จะห่อเมธอด context.SaveChanges () ของฉันไว้ใน try / catch และสร้างไฟล์ข้อความเอาท์พุทที่ช่วยให้ฉันอ่านข้อผิดพลาดได้อย่างชัดเจนและรหัสนี้ยังบันทึกเวลาด้วย - สะดวกถ้าคุณ พบข้อผิดพลาดมากกว่าหนึ่งครั้งในเวลาที่ต่างกัน!

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

5

สิ่งที่ฉันพบ ... เมื่อฉันได้รับข้อผิดพลาด 'EntityValidationErrors' คือ .... ฉันมีฟิลด์ในฐานข้อมูลของฉัน 'db1' ในตาราง 'tbladdress' เป็น 'address1' ซึ่งมีขนาด 100 (เช่น address varchar (100) เป็นโมฆะ) และฉันส่งค่ามากกว่า 100 ตัวอักษร .. และสิ่งนี้นำไปสู่ข้อผิดพลาดขณะบันทึกข้อมูลไปยังฐานข้อมูล ....

ดังนั้นคุณต้องตรวจสอบข้อมูลที่คุณส่งผ่านไปยังฟิลด์


1
ฉันซาบซึ้งคำตอบนี้เพราะจริง ๆ แล้วมันช่วยฉันแก้ไขข้อผิดพลาด ตารางที่ฉันบันทึกลงใน db ของฉันมีnot nullคอลัมน์ทั้งหมดดังนั้นเมื่อฉันเพิ่มข้อมูลลงในองค์ประกอบทั้งหมดก่อนที่ฉันdb.SaveChanges()จะได้รับไม่มีข้อผิดพลาด
BinaryJoe01

3

มันใช้งานได้สำหรับฉัน

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

วางเบรกพอยต์บนถ้าคำสั่ง จากนั้นคุณสามารถตรวจสอบ modelState ในหน้าต่างดีบั๊ก ในทุกค่าคุณสามารถดูว่ามีข้อผิดพลาดและแม้แต่ข้อความแสดงข้อผิดพลาด แค่นั้นแหละ. เมื่อคุณไม่ต้องการมันอีกต่อไปเพียงแค่ลบหรือแสดงความคิดเห็นบรรทัด

ฉันหวังว่านี่จะช่วยได้

หากถูกถามฉันสามารถให้ภาพหน้าจอโดยละเอียดในหน้าต่างแก้ไขข้อบกพร่อง


3

ตามที่กล่าวไว้ในโพสต์อื่น ๆ เพียงแค่จับข้อยกเว้นในคลาส DbEntityValidationException ซึ่งจะให้สิ่งที่คุณต้องการในระหว่างกรณีข้อผิดพลาด

 try
 {
  ....
 }
 catch(DbEntityValidationException ex)
 {
  ....
 }

2

ฉันประสบข้อผิดพลาดนี้มาก่อน

เมื่อฉันพยายามอัปเดตฟิลด์เฉพาะในโมเดลของฉันในเอนทิตี framwork

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

และตามคำตอบข้างต้น

ฉันพบข้อความตรวจสอบ The SignerName field is required.

ซึ่งชี้ไปที่ฟิลด์ในโมเดลของฉัน

และเมื่อฉันตรวจสอบคีมาฐานข้อมูลของฉันฉันพบ

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นนอกValidationExceptionจะมีสิทธิที่จะยกระดับ

และตามสาขานี้ฉันต้องการให้เป็นโมฆะ (ฉันไม่รู้ว่าฉัน messed)

ดังนั้นฉันจึงเปลี่ยนฟิลด์นั้นเพื่ออนุญาตให้ Null และด้วยรหัสของฉันนี้จะไม่ให้ข้อผิดพลาดนี้อีกครั้ง

ดังนั้นข้อผิดพลาดนี้อาจจะเกิดขึ้นหากคุณทำให้ข้อมูลในฐานข้อมูลของคุณสมบูรณ์


1
ข้อยกเว้นควรได้รับการยกหรือไม่ไม่ใช่ประเด็นที่นี่ ถัดไปคุณกำลังตัดมุมบางส่วนที่นี่ เมื่อต้องการฟิลด์ในสกีมาฐานข้อมูลคุณต้องการมากกว่านั้นเพื่อDbEntityValidationExceptionเพิ่ม
Gert Arnold

2

โปรดตรวจสอบค่าของฟิลด์ที่คุณส่งผ่านถูกต้องและเป็นไปตามฟิลด์ฐานข้อมูล ตัวอย่างเช่นจำนวนอักขระที่ส่งผ่านในฟิลด์เฉพาะนั้นน้อยกว่าอักขระที่กำหนดในฟิลด์ตารางฐานข้อมูล


1

หากคุณกำลังใช้IISกับของ Windows authentificationและEntity Framework , authorizeต้องระวังในการใช้งาน

ฉันพยายามทำPOSTโดยไม่ได้รับอนุญาต แต่ใช้งานไม่ได้และได้รับข้อผิดพลาดนี้ในdb.SaveChangesAsync();ขณะที่คำกริยาอื่น ๆ ทั้งหมดGETและDELETEทำงานได้

แต่เมื่อฉันเพิ่ม AuthorizeAttribute เป็นคำอธิบายประกอบมันใช้งานได้

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

1

นี่เป็นอีกวิธีในการทำแทนที่จะใช้ลูป foreach เพื่อดูภายใน EntityValidationErrors แน่นอนคุณสามารถจัดรูปแบบข้อความตามความชอบของคุณ:

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

1

ในกรณีของฉันมันเป็นเพราะความยาวของเขตข้อมูลฐานข้อมูลน้อยกว่าความยาวของช่องใส่

ตารางฐานข้อมูล

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

อินพุตของฉัน

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

ค่าสำหรับUsername lengthคือ5ซึ่งคือlessthan6

... นี่อาจช่วยใครซักคน


0

ตรวจสอบว่าคุณมีNot Nullข้อ จำกัด ในคอลัมน์ตารางของคุณและคุณไม่ผ่านค่าสำหรับคอลัมน์นั้นในขณะที่การดำเนินการแทรก / ปรับปรุง ที่ทำให้เกิดข้อยกเว้นนี้ในกรอบงานเอนทิตี


0

ฉันยังประสบปัญหาเดียวกัน ฉันอัพเดต. edmx ของฉันจากฐานข้อมูลหลังจากนั้นข้อยกเว้นได้หายไป


0

ข้อผิดพลาดนี้เกิดขึ้นส่วนใหญ่เนื่องจากขนาดของเขตข้อมูล ตรวจสอบขนาดฟิลด์ทั้งหมดในตารางฐานข้อมูล


0

ก็ยังดิ้นรนกับข้อผิดพลาดนี้และตามหัวข้อที่นี่และคำตอบนี้สามารถคิดตัวอย่างเพื่อคัดลอก / วางโดยไม่จำเป็นต้องคิดออกสิ่งที่จะต้องนำเข้า (ดีสำหรับผู้เริ่มต้น C #) รหัสด้านล่าง:

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);
    }
  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.