EF Code First: Nuget paket konsolundan 'EntityValidationErrors' özelliğini nasıl görebilirim?


127

Bunun için bir kaybım var:

Sınıflarımı bir varlık çerçevesi (4.1.3) kodu ilk yaklaşımı için tanımladım. Seed'e başlayana kadar her şey yolundaydı (tabloları oluşturuyordum vb.).

Şimdi yaptığım zaman

Add-Migration "remigrate" ; Update-Database;

Paket konsolunda bir hata alıyorum "Bir veya daha fazla varlık için doğrulama başarısız oldu. Daha fazla ayrıntı için" EntityValidationErrors "özelliğine bakın."

Seed () yöntemimde bir kesme noktam var, ancak proje çalışmıyorken bunu konsolda çalıştırdığım için, ayrıntılara nasıl ulaşılacağı konusunda bilgim yok (PS - İş parçacığı Doğrulamanın başarısız olduğunu gördüm Özelliği nasıl görebileceğimi gösteren Entity Framework kullanarak SQL Server Veritabanına değişiklikleri kaydederken bir veya daha fazla varlık için .)

Seed () yöntemimin bir sorunu olduğunu biliyorum çünkü yöntem çağrısından hemen sonra bir dönüş koyarsam hata ortadan kalkar. Öyleyse, doğrulama hatasının ne olduğunu görebilmek için kesme noktamı nasıl ayarlayabilirim? Bir çeşit kayıp. Yoksa nuget konsolunda izlemenin başka bir yolu var mı?


Hızlı güncelleme: Hataya neyin neden olduğunu bulana kadar yöntemimdeki her değişkeni sistematik olarak izleyerek sorunumu çözdüm. Yine de sorumun cevabını bilmek istiyorum, çünkü bu çok daha hızlı olacak!
jeremy

Bence taşıma işlemini programlı olarak çalıştırabilir ve ardından istisnayı yakalayabilir ve hataları yineleyebilirsiniz. İdeal değil ama size ihtiyacınız olan ayrıntıları verebilir.
Pawel

Yanlış cevap, cevapların başında geldiğinde sinir bozucu ve tüm övgüleri alıyor StackOverflow'un açıkça yetersiz kaldığı bir yer!
jwize

Yanıtlar:


216

Ben de son zamanlarda bundan rahatsız oldum. Bunu, Seed yöntemindeki Configuration sınıfına bir sarmalayıcı işlevi koyarak düzelttim ve bunun yerine işlevim için SaveChangesyapılan çağrıları değiştirdim. Bu işlev, EntityValidationErrorskoleksiyondaki hataları basitçe numaralandırır ve İstisna mesajının ayrı ayrı sorunları listelediği bir istisnayı yeniden atar. Bu, çıktının NuGet paket yöneticisi konsolunda görünmesini sağlar.

Kod aşağıdaki gibidir:

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

Tohum yönteminizdeki çağrıları context.SaveChanges()ile değiştirin SaveChanges(context).


Richard, sonunda! Fikri olan biri. Denediğimde bu soruya geri döneceğim.
jeremy

Bu gerçekten :) nasties izini yardımcı olur
Eminem

3
Bu tekniği kullandım ama bunun yerine bağlam içinde kayıt değişikliklerinin geçersiz kılınmasını kullandım. public override int SaveChanges() bağlamın içinde.
Kirsten Greed

5
Aşağıda cevapladığım gibi kısmi sınıfları kullanmak daha etkilidir.
jwize

1
Çekirdek yönteminizde UserManager işlemleri yapıyorsanız, bu değişiklik çıktıdaki doğrulama hatalarını içermez, @jwize cevabına göre DBContext SaveChanges, SaveChangesAsync ve SaveChangesAsync (CT) yöntemlerini geçersiz kılmanız gerekir.
Carl

115

Kısmi Sınıf Tanımıyla DBContext Sınıfınızı Genişletin!

DbContext'inizin sınıf tanımına bakarsanız, aşağıdaki gibi olacaktır:

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

Böylece, başka bir dosyada aynı tanımı oluşturabilir ve istediğiniz parçaları geçersiz kılabilirsiniz.

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

Kısmi sınıfları ile fikrine fark --did DBContext kısmi class-- olduğunu sen oluşturulduktan bir sınıf uzatmak (veya birden fazla dosya içine dersleri organize) ve bizim durumumuzda biz de istiyoruz olmasıdır geçersiz SaveChanges yöntemi DbContext'e eklenen kısmi bir sınıfın içinden .

Bu şekilde, her yerde mevcut tüm DbContext / SaveChanges çağrılarından hata ayıklama bilgileri alabiliriz ve Tohum kodunuzu veya geliştirme kodunuzu hiç değiştirmemiz gerekmez.

Yapacağım şey budur ( NOT , sadece kendi yazılan DbContext kısmi sınıfımızda SaveChanges yöntemini geçersiz kılmam , OLUŞTURULAN DEĞİL ). Ayrıca, kısmi sınıfınızın doğru ad alanını kullandığından emin olun, yoksa kafanızı duvara çarparsınız.

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

Sen bir dahisin ...!
Florian F.

Harika çözüm. İnsanlar oy kullanmadan önce tüm cevapları okumalı.
Guilherme de Jesus Santos

3
Ayrıca SaveChangesAsync ve SaveChangesAsync (CancellationToken) 'i de geçersiz kılmalısınız - en azından kodun ilk durumu budur, önce model / db hakkında emin değilsiniz.
Carl

@jwize. Cevabınız veritabanımda ilk istisna işleme sorunlarını modellememe yardımcı oldu. harika cevap
3355307

1
CodeFirst kullanılırken DbContext açıkça oluşturulmaz. Ancak, tasarımcıyı kullandığınızda, DbContext ve Entity sınıfları oluşturulur ve kısmi bir sınıf kullanılarak geçersiz kılınmalıdır.
jwize

35

Richards cevabını bir uzatma yöntemine çevirdim:

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

Şöyle arayın:

context.SaveChangesWithErrors();

4

Craigvl sürümünü C # 'a çevirdim. Context.SaveChanges () eklemek zorunda kaldım; benim için aşağıdaki gibi çalışması için.

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, beni doğru yola getirdiğiniz için teşekkürler (aynı sorunu yaşıyordu), aşağıdaki, taşıma yapılandırması tohum yönteminde benim için çalışan sarmalayıcı olmadan bir alternatiftir:

 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

Daha sonra paket yöneticisi konsolunda istisnayı görebildi. Umarım bu birine yardımcı olur.


-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
Metninizin bir kod bloğu içinde olmaması kodunuzu biçimlendirdiğinizde iyi olur.
jmattheis

bu muhtemelen şimdiye kadar gördüğüm en kötü biçimlendirilmiş yığın aşımı cevabı
yığın aşımı
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.