Kode EF Pertama: Bagaimana saya melihat properti 'EntityValidationErrors' dari konsol paket nuget?

127

Saya bingung untuk ini:

Saya telah mendefinisikan kelas saya untuk pendekatan kerangka kerja entitas (4.1.3) pertama. Semuanya baik-baik saja (saya membuat tabel dll) sampai saya mulai Seed.

Sekarang ketika saya melakukan

Add-Migration "remigrate" ; Update-Database;

Saya mendapatkan kesalahan pada konsol paket "Validasi gagal untuk satu entitas atau lebih. Lihat properti 'EntityValidationErrors' untuk detail lebih lanjut."

Saya memiliki breakpoint dalam metode Seed () saya tetapi karena saya menjalankan ini pada konsol ketika proyek tidak berjalan, saya tidak tahu bagaimana cara untuk mendapatkan rincian (PS - Saya telah melihat thread Validasi gagal untuk satu atau lebih entitas sambil menyimpan perubahan ke Database SQL Server menggunakan Entity Framework yang menunjukkan bagaimana saya bisa melihat properti.)

Saya tahu bahwa metode Seed () saya memiliki masalah karena jika saya mengembalikan tepat setelah panggilan metode, kesalahan hilang. Jadi bagaimana cara mengatur breakpoint saya sehingga saya bisa melihat apa kesalahan validasi itu? Agak hilang. Atau ada cara lain untuk melacaknya di konsol nuget ??

Jeremy
sumber
Pembaruan cepat: Saya memecahkan masalah saya dengan secara sistematis melacak setiap variabel dalam metode saya sampai saya menemukan apa yang menyebabkan kesalahan. Namun, saya masih ingin tahu jawaban pertanyaan saya karena itu akan jauh lebih cepat!
jeremy
Saya pikir Anda bisa menjalankan migrasi secara terprogram dan kemudian menangkap pengecualian dan beralih pada kesalahan. Ini tidak ideal tetapi bisa memberi Anda detail yang Anda butuhkan.
Pawel
Frustasi ketika jawaban yang salah ada di bagian atas jawaban dan mendapatkan semua pujian. Tempat di mana StackOverflow jelas gagal!
Jwize
Jika Anda menggunakan Entity Framework, Anda dapat melihat jawaban saya di Solusi untuk “Validasi gagal untuk satu entitas atau lebih. Lihat properti 'EntityValidationErrors' untuk detail lebih lanjut . Semoga ini bisa membantu ...
Murat Yıldız

Jawaban:

216

Saya merasa terganggu dengan hal ini baru-baru ini juga. Saya memperbaikinya dengan meletakkan fungsi wrapper di kelas Konfigurasi dalam metode Seed, dan menggantikan panggilan SaveChangesdengan panggilan ke fungsi saya. Fungsi ini hanya akan menyebutkan kesalahan dalam EntityValidationErrorskoleksi, dan rethrow pengecualian di mana pesan Pengecualian daftar masalah individu. Ini membuat output muncul di konsol manajer paket NuGet.

Kode berikut:

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

Cukup ganti panggilan ke context.SaveChanges() dengan SaveChanges(context)dalam metode seed Anda.

Richard
sumber
Richard, akhirnya! Seseorang yang punya ide. Saya akan kembali ke pertanyaan ini begitu saya mencobanya.
jeremy
Ini sangat membantu melacak nasties :)
Eminem
3
Saya menggunakan teknik ini tetapi menggunakan override savechanges dalam konteks sebagai gantinya. public override int SaveChanges() di dalam konteks.
Kirsten Greed
5
Ini lebih efektif menggunakan kelas parsial seperti yang saya jawab di bawah ini.
jwize
1
Jika Anda melakukan operasi UserManager dalam metode seed Anda maka perubahan ini tidak akan menyertakan kesalahan validasi dalam output, Anda perlu mengganti metode DBContext SaveChanges, SaveChangesAsync dan SaveChangesAsync (CT) sesuai jawaban @jwize.
Carl
115

Perpanjang Kelas DBContek Anda Sudah Dengan Definisi Kelas Sebagian!

Jika Anda melihat definisi kelas untuk DbContext Anda, itu akan menjadi seperti berikut:

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

Jadi, di file lain Anda dapat membuat definisi yang sama dan mengganti bagian yang Anda inginkan.

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

Seluruh ide dengan kelas parsial --did Anda melihat DbContext adalah class-- parsial adalah bahwa Anda dapat memperpanjang kelas yang telah dihasilkan (atau mengatur kelas menjadi beberapa file) dan dalam kasus kami, kami juga ingin menimpa para SaveChanges metode dari dalam kelas parsial yang menambah DbContext .

Dengan cara ini kita bisa mendapatkan informasi kesalahan debug dari semua panggilan DbContext / SaveChanges yang ada di mana-mana dan tidak perlu mengubah kode Seed atau kode pengembangan sama sekali.

Inilah yang akan saya lakukan ( Perhatikan perbedaannya adalah bahwa saya hanya mengganti metode SaveChanges di kelas parsial DbContext buatan kami sendiri , BUKAN SATU HAL YANG DIHASILKAN ). Juga, pastikan Anda sebagian kelas menggunakan namespace yang benar atau Anda akan membenturkan kepala Anda ke dinding.

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
        }
    }
}
jwize
sumber
Kamu jenius ...!
Florian F.
Solusi bagus Orang-orang harus membaca semua jawaban sebelum upvoting.
Guilherme de Jesus Santos
3
Anda juga harus mengganti SaveChangesAsync dan SaveChangesAsync (CancellingToken) juga - setidaknya itu yang terjadi dengan kode terlebih dahulu, tidak yakin tentang model / db terlebih dahulu.
Carl
@ jwize. jawaban Anda membantu saya dalam pemodelan pertama saya pengecualian database menangani masalah. jawaban bagus
3355307
1
Saat menggunakan CodeFirst, DbContext jelas tidak dihasilkan. Namun, ketika Anda menggunakan desainer, kelas DbContext dan Entity dihasilkan dan harus diganti menggunakan kelas parsial.
jwize
35

Saya mengonversi jawaban Richards ke metode ekstensi:

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

Panggil seperti ini:

context.SaveChangesWithErrors();
Gordo
sumber
4

Saya mengonversi versi craigvl ke C # Saya harus menambahkan context.SaveChanges (); agar bisa bekerja untuk saya seperti di bawah ini.

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());
}
Ben Pretorius
sumber
3

Terima kasih Richard karena telah membawa saya ke jalur yang benar (memiliki masalah yang sama) di bawah ini adalah alternatif tanpa pembungkus ini berfungsi untuk saya dalam metode seed konfigurasi migrasi:

 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

Apakah kemudian dapat melihat pengecualian di konsol manajer paket. Semoga ini bisa membantu seseorang.

craigvl
sumber
-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

Muhammad Usama
sumber
1
Akan lebih baik ketika Anda memformat kode Anda bahwa teks Anda tidak di dalam blok kode.
jmattheis
ini mungkin jawaban stackoverflow terformat terburuk yang pernah saya lihat
crazy_crank