2012-04-19 10 views
121

Sono in perdita per questo:Codice EF Primo: come vedo la proprietà 'EntityValidationErrors' dalla console del pacchetto nuget?

Ho definito le mie classi per un primo approccio al codice di entità framework (4.1.3). Tutto andava bene (stavo creando le tabelle, ecc.) Fino a quando ho iniziato a Seed.

Ora, quando faccio il

Add-Migration "remigrate" ; Update-Database; 

ottengo un errore sulla console pacchetto "di convalida non riuscita per una o più entità. Vedi proprietà 'EntityValidationErrors' per maggiori dettagli."

Ho un punto di interruzione nel mio metodo Seed() ma perché sto eseguendo questo sulla console quando il progetto non è in esecuzione, non ho idea di come arrivare ai dettagli (PS - Ho visto il thread Validation failed for one or more entities while saving changes to SQL Server Database using Entity Framework che mostra come posso vedere la proprietà.)

So che il mio metodo Seed() ha un problema perché se inserisco un ritorno subito dopo la chiamata al metodo, l'errore scompare. Quindi, come faccio a impostare il mio punto di interruzione in modo da poter vedere qual è l'errore di convalida? Un pò perso. O c'è un altro modo per rintracciarlo nella console di nuget ??

+0

aggiornamento rapido: ho risolto il problema, monitorando sistematicamente ogni variabile all'interno del mio metodo finché non ho trovato quello che stava causando l'errore. Tuttavia, mi piacerebbe comunque conoscere la risposta alla mia domanda in quanto sarebbe molto più veloce! – jeremy

+0

Penso che potresti eseguire la migrazione a livello di codice e quindi rilevare l'eccezione e iterare sugli errori. Non è l'ideale, ma potrebbe fornirti i dettagli di cui hai bisogno. – Pawel

+0

Frustrante quando la risposta sbagliata è in cima alle risposte e ottiene tutto il merito. Un posto dove StackOverflow chiaramente cade a breve! – jwize

risposta

205

Recentemente mi sono infastidito anche da questo. L'ho risolto inserendo una funzione wrapper nella classe Configuration nel metodo Seed e sostituendo le chiamate allo SaveChanges con le chiamate alla mia funzione. Questa funzione dovrebbe semplicemente enumerare gli errori all'interno della raccolta EntityValidationErrors e reimplicare un'eccezione in cui il messaggio Eccezione elenca i singoli problemi. Ciò rende l'output visualizzato nella console del gestore pacchetti NuGet.

Codice segue:

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

Basta sostituire le chiamate al context.SaveChanges() con SaveChanges(context) nel metodo seme.

+0

Richard, finalmente! Qualcuno con un'idea. Tornerò su questa domanda una volta provata. – jeremy

+2

Ha funzionato brillantemente - grazie per la vostra soluzione. – daveywc

+0

Questo aiuta davvero a rintracciare i fastidi :) – Eminem

3

Richard grazie per avermi sulla strada giusta (aveva lo stesso problema) Di seguito è un'alternativa senza l'involucro questo ha funzionato per me nel metodo di migrazione seme di configurazione:

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 

è stato poi in grado di vedere l'eccezione nella console del gestore pacchetti. Spero che questo aiuti qualcuno.

4

Ho convertito la versione di craigvl in C# Ho dovuto aggiungere context.SaveChanges(); in modo che funzioni per me come di seguito.

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

mi sono convertito Richards risposta ad un metodo di estensione:

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

chiamata in questo modo:

context.SaveChangesWithErrors(); 
107

prolungare il Class DbContext Già Con una definizione di classe parziale!

Se si guarda alla definizione di classe per i vostri DbContext sarà qualcosa di simile al seguente:

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

Così, in un altro file è possibile creare la stessa definizione e ignorare le parti che si desidera.

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

L'idea con classi parziali --did si nota la DbContext è un parziale di class-- è che si può estendere una classe che è stato generato (o di organizzare le classi in file multipli) e nel nostro caso vogliamo anche sostituire il metodo SaveChanges all'interno di una classe parziale che si aggiunge allo DbContext.

In questo modo è possibile ottenere informazioni di debug degli errori da tutte le chiamate DbContext/SaveChanges esistenti ovunque e non è necessario modificare il codice seme o il codice di sviluppo.

Questo è quello che vorrei fare (NOTA la differenza è che ho solo l'override metodo SaveChanges nel nostro autore DbContext classe parziale, NON IL GENERATO UN). Inoltre, assicurati che la classe parziale utilizzi lo spazio dei nomi corretto o sbatterai la testa contro il muro.

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

Ci sono alcune risposte che vorrei poter votare due volte :) –

+0

Sei un genio ...! –

+0

Ottima soluzione. Le persone dovrebbero leggere tutte le risposte prima di fare upvoting. –

0

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

+0

Sarebbe bello quando si formatta il codice che il testo non si trova all'interno di un blocco di codice. – jmattheis

Problemi correlati