首页 文章

EF Code First:如何从nuget包控制台查看'EntityValidationErrors'属性?

提问于
浏览
122

我为此感到茫然:

我已经为实体框架(4.1.3)代码第一种方法定义了我的类 . 一切都很好(我正在制作 table 等),直到我开始播种 .

现在当我这样做的时候

Add-Migration "remigrate" ; Update-Database;

我在程序包控制台上收到错误“一个或多个实体的验证失败 . 有关详细信息,请参阅'EntityValidationErrors'属性 . ”

我的Seed()方法中有一个断点但因为我对如何获取细节毫无头绪(PS - 我看过线程Validation failed for one or more entities while saving changes to SQL Server Database using Entity Framework,它显示了我如何看到该属性 . )

我知道我的Seed()方法有问题,因为如果我在方法调用之后立即返回,则错误消失 . 那么如何设置断点以便我可以看到验证错误是什么?有点失落 . 或者是否有其他方法可以在nuget控制台中跟踪它?

6 回答

  • 210

    我最近也对此感到恼火 . 我通过在Seed方法的Configuration类中放置一个包装器函数来修复它,并通过调用我的函数来替换对 SaveChanges 的调用 . 此函数将简单地枚举 EntityValidationErrors 集合中的错误,并重新抛出异常消息列出各个问题的异常 . 这使得输出显示在NuGet包管理器控制台中 .

    代码如下:

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

    只需在种子方法中用 SaveChanges(context) 替换 context.SaveChanges() 的调用 .

  • 4

    Extend Your DBContext Class Already With a Partial Class Definition!

    如果您查看DbContext的类定义,它将类似于以下内容:

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

    因此,在另一个文件中,您可以创建相同的定义并覆盖您想要的部分 .

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

    部分类的整个想法 - 你注意到 DbContext 是一个部分类 - 是你可以扩展一个已生成的类(或将类组织成多个文件),在我们的例子中我们也想 override SaveChanges 方法从添加到 DbContext 的部分类中 .

    这样我们就可以从所有现有的DbContext / SaveChanges调用中获取错误调试信息,而不必更改种子代码或开发代码 .

    这就是我要做的事情( NOTE ,不同之处在于我只是在我们自己编写的 DbContext 部分类中重写了SaveChanges方法,而不是生成的一个) . 另外,请确保您的部分课程使用 correct namespace ,否则您将撞到墙上 .

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

    我将Richards的答案转换为扩展方法:

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

    像这样打电话:

    context.SaveChangesWithErrors();
    
  • 35

    我将craigvl的版本转换为C#我必须添加context.SaveChanges();为了它对我有用,如下所示 .

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

    理查德感谢让我在正确的道路上(有相同的问题)下面是一个替代品,没有包装器,这在迁移配置种子方法中对我有用:

    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
    

    然后能够在包管理器控制台中看到异常 . 希望这有助于某人 .

  • 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
    

相关问题