Brakuje mi tego:
Zdefiniowałem moje klasy dla frameworka encji (4.1.3) kodu najpierw podejście. Wszystko było w porządku (tworzyłem tabele itp.), Dopóki nie zacząłem Seed.
Teraz, kiedy robię
Add-Migration "remigrate" ; Update-Database;
W konsoli pakietu pojawia się błąd „Walidacja nie powiodła się dla co najmniej jednej jednostki. Aby uzyskać więcej informacji, zobacz właściwość„ EntityValidationErrors ””.
Mam punkt przerwania w mojej metodzie Seed (), ale ponieważ uruchamiam to na konsoli, gdy projekt nie jest uruchomiony, nie mam pojęcia, jak dotrzeć do szczegółów (PS - widziałem wątek Walidacja nie powiodła się dla co najmniej jednej jednostki podczas zapisywania zmian w bazie danych SQL Server przy użyciu Entity Framework, która pokazuje, jak mogę zobaczyć tę właściwość.)
Wiem, że moja metoda Seed () ma problem, ponieważ jeśli wstawię powrót bezpośrednio po wywołaniu metody, błąd zniknie. Jak więc ustawić punkt przerwania, aby zobaczyć, na czym polega błąd walidacji? Trochę przegrane. Czy jest jakiś inny sposób śledzenia go w konsoli nuget?
Odpowiedzi:
Ostatnio też mnie to zirytowało. Naprawiłem to, umieszczając funkcję opakowującą w klasie Configuration w metodzie Seed i zamiast tego zastąpiłem wywołania
SaveChanges
funkcji wywołaniami mojej funkcji. Ta funkcja po prostu wyliczy błędy wEntityValidationErrors
kolekcji i ponownie zgłosi wyjątek, w którym komunikat o wyjątku zawiera listę poszczególnych problemów. Dzięki temu dane wyjściowe są wyświetlane w konsoli Menedżera pakietów NuGet.Kod następujący:
/// <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 } }
Wystarczy zastąpić wywołań
context.SaveChanges()
zeSaveChanges(context)
w metodzie nasion.źródło
public override int SaveChanges()
wewnątrz kontekstu.Rozszerz swoją klasę DBContext już z częściową definicją klasy!
Jeśli spojrzysz na definicję klasy dla swojego DbContext, będzie to coś podobnego do następującego:
// DatabaseContext.cs -- This file is auto generated and thus shouldn't be changed. public partial class [DatabaseContextName] : DbContext { ... }
Tak więc w innym pliku możesz utworzyć tę samą definicję i nadpisać części, które chcesz.
// partialDatabaseContext.cs -- you can safely make changes // that will not be overwritten in here. public partial class [DatabaseContextName] : DbContext { // Override defaults here }
Cały pomysł z częściowym klas --did można zauważyć DbContext jest częściowym class-- jest to, że można rozszerzyć klasę, który został wygenerowany (lub zorganizować zajęcia na kilka plików), aw naszym przypadku chcemy też zastąpić ten SaveChanges metody z klasy częściowej, która dodaje do DbContext .
W ten sposób możemy uzyskać informacje o błędach debugowania ze wszystkich istniejących wywołań DbContext / SaveChanges wszędzie i nie musimy w ogóle zmieniać kodu początkowego ani kodu programistycznego.
Oto, co bym zrobił ( UWAGA różnica polega na tym, że po prostu nadpisuję metodę SaveChanges w naszej własnej autorskiej klasie częściowej DbContext , a NIE w GENEROWANEJ ). Upewnij się również, że część zajęć używa poprawnej przestrzeni nazw, w przeciwnym razie będziesz walił głową o ścianę.
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 } } }
źródło
Przekonwertowałem odpowiedź Richardsa na metodę rozszerzenia:
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 } }
Zadzwoń tak:
źródło
Przekonwertowałem wersję Craigvla na C # Musiałem dodać context.SaveChanges (); aby działało dla mnie jak poniżej.
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()); }
źródło
Richard dzięki za doprowadzenie mnie na właściwą ścieżkę (miał ten sam problem) poniżej jest alternatywą bez opakowania, które zadziałało dla mnie w metodzie inicjującej konfiguracji migracji:
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
Był wtedy w stanie zobaczyć wyjątek w konsoli menedżera pakietów. Mam nadzieję, że to komuś pomoże.
źródło
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
źródło