web-dev-qa-db-fra.com

Code EF en premier: Comment puis-je voir la propriété 'EntityValidationErrors' depuis la console du paquet nuget?

Je suis perdu pour cela:

J'ai défini mes classes pour une approche d'abord de code d'entité framework (4.1.3). Tout allait bien (j'ai créé les tables, etc.) jusqu'à ce que je commence à Seed.

Maintenant quand je fais le

Add-Migration "remigrate" ; Update-Database;

Une erreur s'est produite sur la console du package "Echec de la validation pour une ou plusieurs entités. Voir la propriété 'EntityValidationErrors' pour plus de détails."

J'ai un point d'arrêt dans ma méthode Seed (), mais comme je l'exécute sur la console lorsque le projet ne fonctionne pas, je ne sais pas comment accéder aux détails (PS - j'ai vu le fil - La validation a échoué pour une ou plusieurs entités lors de l'enregistrement des modifications dans la base de données SQL Server à l'aide de Entity Framework , ce qui montre comment je peux voir la propriété.)

Je sais que ma méthode Seed () a un problème car si je mets un retour juste après l'appel de la méthode, l'erreur disparaît. Alors, comment puis-je définir mon point d'arrêt pour que je puisse voir quelle est l'erreur de validation? Un peu perdu. Ou y a-t-il un autre moyen de le tracer dans la console Nuget?

124
jeremy

Je me suis aussi énervé récemment. Je l'ai corrigé en plaçant une fonction wrapper dans la classe Configuration dans la méthode Seed, et ai remplacé les appels à SaveChanges par des appels à ma fonction. Cette fonction énumérerait simplement les erreurs. dans la collection EntityValidationErrors, puis redistribuez une exception dans laquelle le message Exception répertorie les problèmes individuels, ce qui permet d'afficher la sortie dans la console du gestionnaire de paquets NuGet.

Le code suit:

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

Il suffit de remplacer les appels à context.SaveChanges() par SaveChanges(context) dans votre méthode de départ.

212
Richard

Étendez votre classe DBContext déjà avec une définition de classe partielle!

Si vous regardez la définition de classe pour votre DbContext, cela ressemblera à ceci:

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

Ainsi, dans un autre fichier, vous pouvez créer la même définition et remplacer les parties que vous souhaitez.

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

L'idée avec les classes partielles - avez-vous remarqué que DbContext est une classe partielle - est que vous pouvez étendre une classe qui a été générée (ou organise les classes en plusieurs fichiers) et dans notre cas nous voulons aussi override la méthode SaveChanges depuis une classe partielle qui ajoute à la - DbContext.

De cette façon, nous pouvons obtenir des informations de débogage d’erreur de tous les appels DbContext/SaveChanges existants partout et ne pas avoir à changer votre code Seed ou votre code de développement.

C’est ce que je ferais ( NOTE la différence, c’est que je substitue simplement la méthode SaveChanges dans notre propre classe DbContext partielle, PAS CELUI GÉNÉRÉ ). De plus, assurez-vous que votre classe partielle utilise le espace de noms correct ou vous cognerez votre tête contre le mur.

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

J'ai converti Richards answer en une méthode d'extension:

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

Appelle comme ça:

context.SaveChangesWithErrors();
35
Gordo

J'ai converti la version de craigvl en C #. J'ai dû ajouter context.SaveChanges (); afin que cela fonctionne pour moi comme ci-dessous.

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

Richard, merci de m'avoir mis sur le droit chemin (avec le même problème), voici une alternative sans le wrapper, cela a fonctionné pour moi dans la méthode de départ de la configuration de la migration:

 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

A pu ensuite voir l'exception dans la console du gestionnaire de packages. J'espère que ça aide quelqu'un.

3
craigvl
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
Muhammad Usama