Xác nhận thất bại cho một hoặc nhiều thực thể. Xem thuộc tính 'EntityValidationErrors' để biết thêm chi tiết


804

Tôi gặp lỗi này khi khởi tạo cơ sở dữ liệu của mình bằng cách tiếp cận mã đầu tiên.

Xác nhận thất bại cho một hoặc nhiều thực thể. Xem thuộc tính 'EntityValidationErrors' để biết thêm chi tiết.

Thành thật mà nói tôi không biết cách kiểm tra nội dung của các lỗi xác nhận. Visual Studio cho tôi thấy rằng đó là một mảng có 8 đối tượng, vì vậy 8 lỗi xác thực.

Điều này đã làm việc với mô hình trước đây của tôi, nhưng tôi đã thực hiện một vài thay đổi mà tôi giải thích bên dưới:

  • Tôi có một enum được gọi là Status, tôi đã thay đổi nó thành một lớp gọi là Status
  • Tôi đã thay đổi lớp ApplicantsPocationHistory để có 2 khóa ngoại vào cùng một bảng

Xin lỗi cho mã dài, nhưng tôi phải dán tất cả. Ngoại lệ được ném vào dòng cuối cùng của đoạn mã sau.

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

Câu trả lời:


1237

Thành thật mà nói tôi không biết cách kiểm tra nội dung của các lỗi xác nhận. Visual Studio cho tôi thấy rằng đó là một mảng có 8 đối tượng, vì vậy 8 lỗi xác thực.

Trên thực tế, bạn sẽ thấy các lỗi nếu bạn truy sâu vào mảng đó trong Visual studio trong quá trình gỡ lỗi. Nhưng bạn cũng có thể bắt ngoại lệ và sau đó viết ra lỗi cho một số cửa hàng ghi nhật ký hoặc bảng điều khiển:

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

EntityValidationErrorslà một bộ sưu tập đại diện cho các thực thể không thể xác thực thành công và bộ sưu tập bên trong ValidationErrorsmỗi thực thể là một danh sách các lỗi ở cấp độ thuộc tính.

Các thông báo xác nhận này thường đủ hữu ích để tìm nguồn gốc của vấn đề.

Biên tập

Một vài cải tiến nhỏ:

Các giá trị của thuộc tính xúc phạm có thể được đưa vào các vòng trong như vậy:

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

Mặc dù gỡ lỗi Debug.Writecó thể thích hợp hơn Console.WriteLinevì nó hoạt động trong tất cả các loại ứng dụng, không chỉ các ứng dụng bảng điều khiển (nhờ @Bart cho ghi chú của mình trong các bình luận bên dưới).

Đối với các ứng dụng web đang được sản xuất và sử dụng Elmah để ghi nhật ký ngoại lệ, hóa ra nó rất hữu ích đối với tôi để tạo một ngoại lệ tùy chỉnh và ghi đè SaveChangesđể ném ngoại lệ mới này.

Loại ngoại lệ tùy chỉnh trông như thế này:

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

SaveChangescó thể được ghi đè theo cách sau:

public class MyContext : DbContext
{
    // ...

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

Một vài nhận xét:

  • Màn hình lỗi màu vàng mà Elmah hiển thị trong giao diện web hoặc trong các email đã gửi (nếu bạn đã định cấu hình đó) hiện hiển thị chi tiết xác thực trực tiếp ở đầu tin nhắn.

  • Ghi đè Messagetài sản trong ngoại lệ tùy chỉnh thay vì ghi đè ToString()có lợi ích là "màn hình vàng chết chóc" (YSOD) tiêu chuẩn của ASP.NET cũng hiển thị thông báo này. Trái ngược với Elmah, YSOD dường như không sử dụng ToString(), nhưng cả hai đều hiển thị thuộc Messagetính.

  • Bao bọc bản gốc DbEntityValidationExceptiondưới dạng ngoại lệ bên trong đảm bảo rằng dấu vết ngăn xếp ban đầu vẫn sẽ có sẵn và được hiển thị trong Elmah và YSOD.

  • Bằng cách đặt điểm dừng trên dòng, throw newException;bạn có thể chỉ cần kiểm tra thuộc newException.Messagetính dưới dạng văn bản thay vì đi sâu vào các bộ sưu tập xác thực, điều này hơi khó xử và dường như không dễ dàng cho mọi người (xem bình luận bên dưới).


87
Khoan vào ngoại lệ không làm gì cả. Nó chỉ nói rằng có một DbEntityValidationResult nhưng không cho phép bạn mở rộng !!
Shumii

30
@Shumii Xem câu trả lời này để mở rộng ngoại lệ.
Cavyn VonDeylen

18
Chỉ để mở rộng một giải pháp thanh lịch. Bạn có thể muốn ghi đè phương thức savechanges trong lớp DbContext của riêng bạn, sau đó thêm khối thử, trong đó khối thử chỉ cố lưu (base.SaveChanges ()) và khối bắt chỉ bắt DbEntityValidationException. Bằng cách này, bạn không cần thêm nó ở mọi nơi bạn lưu các thay đổi của mình.
Milton

7
Điều này đã cứu thịt xông khói của tôi nhiều hơn một lần. Tôi chỉ có thể upvote một lần. Ước gì họ sẽ cho tôi nâng cấp mỗi lần tôi sao chép và dán cái này.
Damon Drake

5
+2 cho mã. Quả thực là một vị cứu tinh :) -1 khi sử dụng Console.WriteLine, tôi ước tính ngày càng có nhiều người viết dự án web sau đó điều khiển các ứng dụng và Debug.Writehoạt động trong cả hai ...
Bart

459

Bạn có thể làm điều đó từ Visual Studio trong quá trình gỡ lỗi mà không cần viết bất kỳ mã nào, thậm chí không phải là một khối bắt.

Chỉ cần thêm một chiếc đồng hồ với tên:

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

Biểu thức đồng hồ $exceptionhiển thị bất kỳ ngoại lệ nào được ném trong bối cảnh hiện tại, ngay cả khi nó chưa được bắt và gán cho một biến.

Dựa trên http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/


39
+1 Cách giải pháp tốt hơn và không yêu cầu thay đổi mã.
Thật

4
+1 cái này rất, rất tiện dụng! Bạn thậm chí không cần phải có một khối thử / bắt. Chỉ cần dán cái này vào danh sách theo dõi khi VS bị hỏng và voila .. bạn đã có lỗi xác thực trước mặt.
theyetiman

40
một vài lần trong năm tôi quên cách làm điều này và tìm câu trả lời này
Justin Moore

3
@zairja Tôi chưa thử nghiệm nó trong vb.net, nhưng có vẻ như biến đó được xác định cho vb.net cũng như trong msdn.microsoft.com/en-us/l Library / ms164891.aspx , tuy nhiên, diễn viên có thể không được định nghĩa cho vb.net và thay vào đó, có lẽ bạn nên thực hiện DirectCast ($ ngoại lệ, System.Data.Entity.Validation.DbEntityValidationException)
yoel halb 16/07/2015

2
Tôi biết rằng "cảm ơn" không được hoan nghênh trong các bình luận nhưng vì mục đích ngăn chặn tôi hàng giờ lãng phí ... cảm ơn!
Luther

105

Điều này thực sự có thể làm điều đó mà không cần phải viết mã:

Trong khối bắt của bạn, thêm một điểm dừng ở dòng mã sau:

catch (Exception exception)
{

}

Bây giờ nếu bạn di chuột lên exceptionhoặc thêm nó vào Watchvà sau đó điều hướng vào các chi tiết ngoại lệ như được hiển thị bên dưới; bạn sẽ thấy (các) cột cụ thể nào đang / đang gây ra sự cố vì lỗi này thường xảy ra khi một ràng buộc bảng bị vi phạm ..

nhập mô tả hình ảnh ở đây

Hình ảnh lớn


4
Cách tiếp cận này rất đơn giản và tận dụng lợi thế của IDE :)
DSnunez

3
Đây là một giải pháp tốt vì nó nhanh chóng, đơn giản, sử dụng IDE và tiết kiệm cho tôi rất nhiều thời gian.
maxshuty

2
Tôi thích cách này "Làm thế nào để trở thành một lập trình viên và không làm mã"
mở và miễn phí vào

1
Cảm ơn bạn. Điều này là đơn giản nhưng thật tuyệt vời khi xem ngoại lệ bằng IDE.
Thomas.Benz

giải pháp hoàn hảo
Neeraj Singh Chouhan

46

Đây là cách bạn có thể kiểm tra nội dung của EntityValidationErrors trong Visual Studio (không cần viết thêm bất kỳ mã nào) tức là trong quá trình Gỡ lỗi trong IDE .

Vấn đề?

Bạn đã đúng, Trình gỡ lỗi của Visual Studio Xem chi tiết Popup không hiển thị các lỗi thực tế bên trong EntityValidationErrorsbộ sưu tập.

nhập mô tả hình ảnh ở đây

Giải pháp!

Chỉ cần thêm biểu thức sau trong cửa sổ Xem nhanh và nhấp vào Đánh giá lại .

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

Trong trường hợp của tôi, hãy xem làm thế nào tôi có thể mở rộng vào ValidationErrors Listbên trong EntityValidationErrorsbộ sưu tập

nhập mô tả hình ảnh ở đây

: Tài liệu tham khảo mattrandle.me bài đăng blog , câu trả lời @ Yoel của


3
Tại sao điều này chưa được sửa chữa? nó sẽ hiển thị lỗi không phải điều gì khác
Geomorillo

2
Lỗi xác nhận cho thấy lỗi thuộc tính, ví dụ. lĩnh vực chủ đề là bắt buộc, câu trả lời tốt, Cảm ơn bạn
hamzeh.hanandeh

1
Tuyệt quá! Nó đã cứu đêm của tôi! :)
Patrick

1
Đây là cách thông minh để hình dung lỗi chính xác trong đồng hồ ... cảm ơn bạn!
Qwerty

39

Để biết cách nhanh chóng để xem lỗi đầu tiên mà không cần thêm đồng hồ, bạn có thể dán lỗi này vào Cửa sổ ngay lập tức:

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

1
Bạn cũng có thể sử dụng $ exception.EntityValidationErrors.SelectMany (x => x.ValidationErrors) .Select (x => x.ErrorMessage) để có được tất cả trong số họ :) IMHO sử dụng cửa sổ trước mắt là câu trả lời tốt nhất
chrispepper1989

15

Cho bất cứ ai làm việc trong 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

Trong khi bạn đang ở chế độ gỡ lỗi trong catch {...}khối, hãy mở cửa sổ "QuickWatch" ( ctrl+ alt+ q) và dán vào đó:

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

hoặc là:

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

Nếu bạn không ở trong thử / bắt hoặc không có quyền truy cập vào đối tượng ngoại lệ.

Điều này sẽ cho phép bạn đi sâu vào ValidationErrors cây. Đó là cách dễ nhất mà tôi đã tìm thấy để có cái nhìn sâu sắc tức thì về những lỗi này.


10

Nếu bạn chỉ đơn giản là bắt một ngoại lệ chung, nó có thể có lợi cho bạn để sử dụng DbEntityValidationException . Loại ngoại lệ này có thuộc tính Lỗi xác thực và tiếp tục mở rộng theo cách của bạn vào chúng, bạn sẽ tìm thấy tất cả các vấn đề.

Ví dụ: nếu bạn đặt điểm dừng trong bẫy, bạn có thể ném những thứ sau vào đồng hồ:

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

Một ví dụ về lỗi là nếu một trường không cho phép null và bạn có một chuỗi null, bạn sẽ thấy nó nói rằng trường là bắt buộc.


9

chỉ cần kiểm tra chiều dài trường bảng cơ sở dữ liệu của bạn. Văn bản đầu vào của bạn lớn hơn độ dài của chiều dài kiểu dữ liệu trường cột


9

Trong gỡ lỗi, bạn có thể nhập mục này vào trường mục nhập trình đánh giá biểu thức QuickWatch:

context.GetValidationErrors()

8

Câu trả lời từ @Slauma thực sự rất hay nhưng tôi thấy rằng nó không hoạt động khi thuộc tính ComplexType không hợp lệ.

Ví dụ: giả sử bạn có một Phonethuộc tính phức tạp PhoneNumber. Nếu thuộc AreaCodetính không hợp lệ, tên thuộc tính trong ve.PropertyNameslà "Phone.AreaCode". Điều này khiến cuộc gọi eve.Entry.CurrentValues<object>(ve.PropertyName)thất bại.

Để khắc phục điều này, bạn có thể chia tên thuộc tính ở mỗi tên ., sau đó lặp lại qua mảng kết quả của tên thuộc tính. Cuối cùng, khi bạn đến dưới cùng của chuỗi, bạn chỉ cần trả lại giá trị của tài sản.

Dưới đây là FormattedDbEntityValidationExceptionlớp của @ Slauma với sự hỗ trợ cho ComplexTypes.

Thưởng thức!

[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
Tôi không thể tin rằng nhiều người đã không ủng hộ điều này, vì đó là một kịch bản rất thực tế và nó đã khiến tôi phát điên trong hai đêm qua. Bạn có biết rằng cảm giác bạn nhận được khi bạn nhận ra việc xử lý lỗi của mình là những gì thực sự gây ra lỗi? Ừ
DJ Grossman

7

Lưu ý rằng Entity.GetType().BaseType.Namecung cấp tên loại bạn đã chỉ định, không phải tên có tất cả các chữ số hex trong tên của nó.


7

Câu trả lời của mỗi @ Slauma và đề xuất của @ Milton Tôi đã mở rộng phương thức lưu tùy chỉnh của lớp cơ sở của chúng tôi bằng một lần thử / bắt sẽ xử lý (và do đó đăng nhập vào nhật ký lỗi của chúng tôi!) Các loại ngoại lệ này.

// 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
Bạn có thể sử dụng trực tiếp sb.AppendFormat ()
Bastien Vandamme

1
Bạn cũng sẽ cần phải thêm dòng mới của riêng mình nếu bạn sử dụng AppendFormat.
vui vẻ

7

Tôi đã phải viết điều này trong cửa sổ ngay lập tức: 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]

để có được sâu vào lỗi chính xác!


6

Sử dụng câu trả lời của @Slauma, tôi đã tạo một đoạn mã (bao quanh với đoạn trích) để sử dụng tốt hơn.

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

Bắt ngoại lệ trong một lần thử và sau đó xem nhanh hoặc ctrl + d & ctrl + q và bạn có thể truy sâu vào EntityValidationErrors.


5

Chỉ cần ném hai xu của tôi vào ...

Trong dbConfiguration.cs của tôi, tôi muốn bọc phương thức context.SaveChanges () của mình vào một thử / bắt và tạo một tệp văn bản đầu ra cho phép tôi đọc (các) Lỗi một cách rõ ràng và mã này cũng đánh dấu thời gian của chúng - tiện dụng nếu bạn chạy vào nhiều hơn một lỗi tại các thời điểm khác nhau!

        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

Những gì tôi tìm thấy ... khi tôi gặp lỗi 'EntityValidationErrors' là .... tôi có một trường trong cơ sở dữ liệu của mình 'db1' trong bảng 'tbladdress' là 'address1' có kích thước 100 (ví dụ địa chỉ varchar (100) null) và tôi đã chuyển giá trị hơn 100 ký tự..và điều này dẫn đến lỗi trong khi lưu dữ liệu vào cơ sở dữ liệu ....

Vì vậy, bạn phải Kiểm tra dữ liệu bạn đang truyền đến trường.


1
Tôi đánh giá cao câu trả lời này vì nó thực sự giúp tôi giải quyết lỗi của mình. Bảng tôi đang lưu trong db của tôi có tất cả not nullcác cột nên một khi tôi đã thêm dữ liệu vào tất cả các phần tử trước đó, tôi db.SaveChanges()không nhận được lỗi.
BinaryJoe01

3

Điều này làm việc cho tôi.

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

Đặt một điểm dừng trên câu lệnh if. Sau đó, bạn có thể kiểm tra modelState trong các cửa sổ gỡ lỗi. Trên mỗi giá trị bạn có thể thấy nếu có lỗi và thậm chí là thông báo lỗi. Đó là nó. Khi bạn không cần nó nữa, chỉ cần xóa hoặc bình luận dòng.

Hy vọng điều này có thể giúp cho bạn.

Nếu được hỏi, tôi có thể cung cấp ảnh chụp màn hình chi tiết trong cửa sổ gỡ lỗi.


3

Như đã đề cập trong các bài viết khác, chỉ cần bắt ngoại lệ trong lớp DbEntityValidationException. Điều này sẽ cung cấp cho bạn bất cứ điều gì bạn yêu cầu trong các trường hợp lỗi.

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

2

Tôi đã đối mặt với lỗi này trước đây

khi tôi cố gắng cập nhật trường cụ thể trong mô hình của mình trong framwork thực thể

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

và theo các câu trả lời trên

Tôi tìm thấy thông báo Xác thực The SignerName field is required.

mà chỉ đến trường trong mô hình của tôi

và khi tôi kiểm tra lược đồ cơ sở dữ liệu của mình, tôi đã tìm thấy

nhập mô tả hình ảnh ở đây

Vì vậy, coure ValidationExceptioncó quyền nâng cao

và theo lĩnh vực này tôi muốn nó là nullable, (tôi không biết làm thế nào tôi làm hỏng nó)

vì vậy tôi đã thay đổi trường đó để cho phép Null và bằng cách này, mã của tôi sẽ không gây ra lỗi này nữa

Vì vậy, lỗi này có thể xảy ra nếu bạn làm mất hiệu lực toàn vẹn dữ liệu của cơ sở dữ liệu của bạn


1
Có hay không một ngoại lệ nên được nêu ra không phải là vấn đề ở đây. Tiếp theo, bạn đang cắt một số góc ở đây. Khi một trường được yêu cầu trong lược đồ cơ sở dữ liệu, bạn cần nhiều hơn thế để DbEntityValidationExceptiontăng.
Gert Arnold

2

Vui lòng kiểm tra giá trị trường bạn đang vượt qua, có hợp lệ và theo các trường cơ sở dữ liệu. Ví dụ, số lượng ký tự được truyền trong một trường cụ thể ít hơn các ký tự được xác định trong trường bảng cơ sở dữ liệu.


1

Nếu bạn đang sử dụng IIS với Khung xác thựcthực thể Windows , hãy cẩn thận khi sử dụng authorize.

Tôi đã cố gắng POSTmà không ủy quyền và nó không hoạt động, và nhận được lỗi này db.SaveChangesAsync();, trong khi tất cả các động từ khác GETDELETE đang hoạt động.

Nhưng khi tôi thêm AuthorizeAttribution làm chú thích, nó đã hoạt động.

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

1

Đây là một cách khác để làm điều đó thay vì sử dụng các vòng lặp foreach để tìm bên trong EntityValidationErrors. Tất nhiên bạn có thể định dạng tin nhắn theo ý thích của riêng bạn:

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

Trong trường hợp của tôi, đó là do độ dài của trường cơ sở dữ liệu nhỏ hơn độ dài của trường đầu vào.

bảng cơ sở dữ liệu

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

Đầu vào của tôi

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

giá trị cho Username length5 mà là lessthan6

... điều này có thể giúp ai đó


0

Kiểm tra xem bạn có Not Nullràng buộc trong các cột trong bảng của mình không và bạn không chuyển giá trị cho cột đó trong khi thao tác chèn / Cập nhật. Điều đó gây ra ngoại lệ này trong khung thực thể.


0

Tôi cũng phải đối mặt với vấn đề tương tự. Tôi đã cập nhật .edmx của mình từ cơ sở dữ liệu sau đó ngoại lệ đã biến mất.


0

Lỗi này xảy ra chủ yếu là do kích thước trường. KIỂM TRA tất cả các kích thước trường trong một bảng cơ sở dữ liệu.


0

Cũng đã đấu tranh với lỗi này và dựa trên chủ đề ở đây và câu trả lời này đã có thể tìm ra đoạn trích để sao chép / dán mà không cần phải tìm ra những gì phải nhập (xuất sắc cho người mới bắt đầu C #), mã bên dưới:

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);
    }
  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.