Mã đầu tiên: Làm cách nào để tôi thấy thuộc tính 'EntityValidationErrors' từ bảng điều khiển gói nuget?


127

Tôi thua lỗ vì điều này:

Tôi đã xác định các lớp của mình cho cách tiếp cận mã đầu tiên của khung thực thể (4.1.3). Mọi thứ đều ổn (tôi đã tạo các bảng, v.v.) cho đến khi tôi bắt đầu Seed.

Bây giờ khi tôi làm

Add-Migration "remigrate" ; Update-Database;

Tôi gặp lỗi trên bảng điều khiển gói "Xác thực 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."

Tôi có một điểm dừng trong phương thức Seed () của mình nhưng vì tôi đang chạy nó trên bàn điều khiển khi dự án không chạy, tôi không biết làm thế nào để đi đến chi tiết (PS - Tôi đã thấy Xác thực luồng không thành công cho một hoặc nhiều thực thể trong khi lưu các thay đổi vào Cơ sở dữ liệu máy chủ SQL bằng cách sử dụng Khung thực thể cho thấy cách tôi có thể xem thuộc tính.)

Tôi biết rằng phương thức Seed () của tôi có vấn đề vì nếu tôi đặt trả về ngay sau khi gọi phương thức, lỗi sẽ biến mất. Vậy làm cách nào để đặt điểm dừng của tôi để tôi có thể xem lỗi xác thực là gì? Mất rồi. Hoặc có một số cách khác để theo dõi nó trong bảng điều khiển nuget ??


Cập nhật nhanh: Tôi đã giải quyết vấn đề của mình bằng cách theo dõi một cách có hệ thống từng biến trong phương thức của tôi cho đến khi tôi tìm thấy nguyên nhân gây ra lỗi. Tuy nhiên, tôi vẫn muốn biết câu trả lời cho câu hỏi của mình vì điều đó sẽ nhanh hơn nhiều!
jeremy

Tôi nghĩ rằng bạn có thể chạy di chuyển theo chương trình và sau đó bắt ngoại lệ và lặp lại các lỗi. Nó không lý tưởng nhưng có thể cung cấp cho bạn các chi tiết bạn cần.
Pawel

Thất vọng khi câu trả lời sai nằm ở đầu câu trả lời và nhận được tất cả tín dụng. Một nơi mà StackOverflow rõ ràng là thiếu!
jwize

Nếu bạn sử dụng Entity Framework, bạn có thể xem câu trả lời của tôi về Giải pháp cho Xác thực xác thực không thành công cho một hoặc nhiều thực thể. Xem thuộc tính 'EntityValidationErrors' để biết thêm chi tiết . Hy vọng điều này sẽ giúp ...
Murat Yıldız

Câu trả lời:


216

Gần đây tôi cũng thấy khó chịu. Tôi đã sửa nó bằng cách đặt một hàm bao bọc trong lớp Cấu hình trong phương thức Seed và thay thế các cuộc gọi SaveChangesbằng các cuộc gọi đến chức năng của tôi. Hàm này chỉ đơn giản là liệt kê các lỗi trong EntityValidationErrorsbộ sưu tập và suy nghĩ lại một ngoại lệ trong đó thông báo Ngoại lệ liệt kê các vấn đề riêng lẻ. Điều này làm cho đầu ra hiển thị trong bảng điều khiển quản lý gói NuGet.

Mã sau:

/// <summary>
/// Wrapper for SaveChanges adding the Validation Messages to the generated exception
/// </summary>
/// <param name="context">The context.</param>
private void SaveChanges(DbContext context) {
    try {
        context.SaveChanges();
    } catch (DbEntityValidationException ex) {
        StringBuilder sb = new StringBuilder();

        foreach (var failure in ex.EntityValidationErrors) {
            sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
            foreach (var error in failure.ValidationErrors) {
                sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                sb.AppendLine();
            }
        }

        throw new DbEntityValidationException(
            "Entity Validation Failed - errors follow:\n" + 
            sb.ToString(), ex
        ); // Add the original exception as the innerException
    }
}

Chỉ cần thay thế các cuộc gọi đến context.SaveChanges()bằng SaveChanges(context)phương pháp hạt giống của bạn.


Richard, cuối cùng! Ai đó với một ý tưởng. Tôi sẽ trở lại câu hỏi này một khi tôi thử nó.
jeremy

Điều này thực sự giúp theo dõi những kẻ xấu :)
Eminem

3
Tôi đã sử dụng kỹ thuật này nhưng thay vào đó sử dụng một ghi đè của savechanges trong bối cảnh. public override int SaveChanges() bên trong bối cảnh.
Kirsten Greed

5
Nó hiệu quả hơn khi sử dụng các lớp một phần như tôi đã trả lời dưới đây.
jwize

1
Nếu bạn đang thực hiện các thao tác UserManager trong phương thức seed của mình thì thay đổi này sẽ không bao gồm các lỗi xác thực trong đầu ra, bạn sẽ cần ghi đè các phương thức DBContext SaveChanges, SaveChangesAsync và SaveChangesAsync (CT) theo câu trả lời @jwize.
Carl

115

Mở rộng lớp DBContext của bạn với định nghĩa lớp một phần!

Nếu bạn nhìn vào định nghĩa lớp cho DbContext của bạn, nó sẽ giống như sau:

// DatabaseContext.cs   -- This file is auto generated and thus shouldn't be changed. 
public partial class [DatabaseContextName] : DbContext { ... }

Vì vậy, trong một tệp khác, bạn có thể tạo cùng một định nghĩa và ghi đè lên các phần bạn muốn.

// partialDatabaseContext.cs  -- you can safely make changes 
// that will not be overwritten in here.
public partial class [DatabaseContextName] : DbContext { // Override defaults here } 

Toàn bộ ý tưởng với các lớp học phần --did bạn nhận thấy các DbContext là một class-- một phần là bạn có thể mở rộng một lớp học mà đã được tạo ra (hoặc tổ chức các lớp học thành nhiều file) và trong trường hợp của chúng tôi, chúng tôi cũng muốn ghi đè lên các SaveChanges phương pháp từ bên trong một lớp một phần thêm vào DbContext .

Bằng cách này, chúng tôi có thể nhận được thông tin sửa lỗi từ tất cả các cuộc gọi DbContext / SaveChanges hiện có ở mọi nơi và không phải thay đổi mã Seed hoặc mã phát triển của bạn.

Đây là những gì tôi sẽ làm ( LƯU Ý sự khác biệt là tôi chỉ ghi đè phương thức SaveChanges trong lớp một phần DbContext do chính chúng tôi tạo ra , KHÔNG PHẢI LÀ MỘT TẠO ). Ngoài ra, hãy chắc chắn rằng lớp một phần của bạn sử dụng không gian tên chính xác nếu không bạn sẽ đập đầu vào tường.

public partial class Database : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            var sb = new StringBuilder();

            foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
                foreach (var error in failure.ValidationErrors)
                {
                    sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine();
                }
            }

            throw new DbEntityValidationException(
                "Entity Validation Failed - errors follow:\n" +
                sb.ToString(), ex
                ); // Add the original exception as the innerException
        }
    }
}

Bạn là một thiên tài ...!
Florian F.

Giải pháp tuyệt vời. Mọi người nên đọc tất cả các câu trả lời trước khi nâng cấp.
Guilherme de Jesus Santos

3
Bạn cũng nên ghi đè SaveChangesAsync và SaveChangesAsync (CancellingToken) - ít nhất đó là trường hợp có mã trước, không chắc chắn về mô hình / db trước.
Carl

@jwize. câu trả lời của bạn đã giúp tôi trong cơ sở dữ liệu của tôi trước tiên mô hình hóa các vấn đề xử lý ngoại lệ. câu trả lời tuyệt vời
3355307

1
Khi sử dụng CodeFirst, DbContext rõ ràng không được tạo. Tuy nhiên, khi bạn sử dụng trình thiết kế, các lớp DbContext và Entity được tạo và phải được ghi đè bằng một lớp một phần.
jwize

35

Tôi đã chuyển đổi câu trả lời của Richards thành một phương thức mở rộng:

  public static int SaveChangesWithErrors(this DbContext context)
    {
        try
        {
            return context.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            StringBuilder sb = new StringBuilder();

            foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
                foreach (var error in failure.ValidationErrors)
                {
                    sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine();
                }
            }

            throw new DbEntityValidationException(
                "Entity Validation Failed - errors follow:\n" +
                sb.ToString(), ex
            ); // Add the original exception as the innerException
        }
    }

Gọi như thế này:

context.SaveChangesWithErrors();

4

Tôi đã chuyển đổi phiên bản của craigvl thành C # Tôi phải thêm bối cảnh.SaveChanges (); để nó làm việc cho tôi như dưới đây.

try
{
    byte[] bytes = System.IO.File.ReadAllBytes(@"C:\Users\sheph_000\Desktop\Rawr.png");
    Console.WriteLine(bytes);

    context.BeverageTypes.AddOrUpdate(
        x => x.Name,
        new AATPos.DAL.Entities.BeverageType { ID = 1, Name = "Sodas" }
        );

    context.Beverages.AddOrUpdate(
        x => x.Name,
        new AATPos.DAL.Entities.Beverage { ID = 1, Name = "Coke", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 2, Name = "Fanta", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 3, Name = "Sprite", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 4, Name = "Cream Soda", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 5, Name = "Pepsi", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" }
        );

    context.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException ex)
{
    var sb = new System.Text.StringBuilder();
    foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation", failure.Entry.Entity.GetType());
        foreach (var error in failure.ValidationErrors)
                {
            sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
            sb.AppendLine();
                }
            }

    throw new Exception(sb.ToString());
}

3

Richard cảm ơn vì đã đưa tôi đi đúng hướng (có cùng một vấn đề) bên dưới là một giải pháp thay thế mà không có trình bao bọc này hoạt động với tôi trong phương pháp hạt giống cấu hình di chuyển:

 Protected Overrides Sub Seed(context As NotificationContext)

        Try
            context.System.AddOrUpdate(
               Function(c) c.SystemName,
                New E_NotificationSystem() With {.SystemName = "System1"},
                New E_NotificationSystem() With {.SystemName = "System2"},
                New E_NotificationSystem() With {.SystemName = "System3"})

            context.SaveChanges()

        Catch ex As DbEntityValidationException

            Dim sb As New StringBuilder

            For Each failure In ex.EntityValidationErrors

                sb.AppendFormat("{0} failed validation" & vbLf, failure.Entry.Entity.[GetType]())

                For Each [error] In failure.ValidationErrors
                    sb.AppendFormat("- {0} : {1}", [error].PropertyName, [error].ErrorMessage)
                    sb.AppendLine()
                Next
            Next

            Throw New Exception(sb.ToString())

        End Try
End Sub

Sau đó đã có thể thấy ngoại lệ trong bảng điều khiển quản lý gói. Hy vọng điều này sẽ giúp được ai đó.


-1

I Also had same model validation problem but successfully catch by myself after lot of thinking;

I use reverse engineering method to catch the problem out of Over 80 + Model Classes;

1> Made copy of dbcontext, changing the name (I add "1" at end and make respective changes in class constructor and initialization etc.

Old:
 
>public class AppDb : IdentityDbContext<ApplicationUser>
>     
> {
> public AppDb(): base("DefaultConnection", throwIfV1Schema: false)
> {
> 
> }
>     
> public static AppDb Create()
>{
>return new AppDb();
>} 

**New:**

>public class AppDb1 : IdentityDbContext<ApplicationUser>
>{
>public AppDb1()
>: base("DefaultConnection", throwIfV1Schema: false)
>{
>}
> 
>public static AppDb1 Create()
> {
> return new AppDb1();
>  }`

...
2> Make changes to Codefirst Migration Configuration from Old DbContext to my new Context.

> internal sealed class Configuration :
> DbMigrationsConfiguration<DAL.AppDb1> { public Configuration() {
> AutomaticMigrationsEnabled = false; }    protected override void
> Seed(DAL.AppDb1 context) {`

3> Comment the Dbsets in new DbContext which was doubt.
4> Apply update migration if succeeded the probelm lye in Commented section.
5> if not then commented section is clear of bug clear.
6> repeat the (4) until found the right place of bug.
7> Happy Codding


1
Sẽ thật tuyệt khi bạn định dạng mã của mình rằng văn bản của bạn không nằm trong khối mã.
jmattheis

đây có lẽ là câu trả lời stackoverflow được định dạng tồi tệ nhất mà tôi từng thấy
crazy_crank
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.