【问题标题】:EF Code First: How do I see 'EntityValidationErrors' property from the nuget package console?EF Code First:如何从 nuget 包控制台查看“EntityValidationErrors”属性?
【发布时间】:2012-04-30 11:35:14
【问题描述】:

我对此感到茫然:

我已经为实体框架 (4.1.3) 代码优先方法定义了我的类。一切都很好(我正在创建表格等),直到我开始播种。

现在我做的时候

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 控制台中跟踪它??

【问题讨论】:

  • 快速更新:我通过系统地跟踪我的方法中的每个变量来解决我的问题,直到找到导致错误的原因。但是,我仍然想知道我的问题的答案,因为这样会更快!
  • 我认为您可以以编程方式运行迁移,然后捕获异常并迭代错误。这并不理想,但可以为您提供所需的详细信息。
  • 当错误答案出现在答案的顶部并获得所有功劳时,令人沮丧。 StackOverflow 明显不足的地方!
  • 如果您使用 Entity Framework,您可以查看我在 Solution for “Validation failed for one or more entities. See 'EntityValidationErrors' property for more details 上的回答。希望这会有所帮助...

标签: asp.net-mvc-3 entity-framework entity-framework-4 nuget


【解决方案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

【讨论】:

  • 当您格式化代码以使您的文本不在代码块内时会很好。
  • 这可能是我见过的格式最差的stackoverflow答案
【解决方案2】:

已经使用部分类定义扩展您的 DBContext 类!

如果您查看 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 是部分类-- 是您可以扩展已生成的类(或组织类到多个文件中),在我们的例子中,我们还希望从添加到 DbContext 的部分类中覆盖 SaveChanges 方法。

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

这就是我要做的(注意不同的是,我只是在我们自己编写的 DbContext 部分类中重写 SaveChanges 方法,不是生成的)。另外,请确保您的部分类使用了正确的命名空间,否则您会碰壁。

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

【讨论】:

  • 你真是个天才……!
  • 很好的解决方案。人们应该在投票前阅读所有答案。
  • 您还应该覆盖 SaveChangesAsync 和 SaveChangesAsync(CancellationToken) - 至少代码优先是这种情况,首先不确定模型/数据库。
  • @jwize,不知道 DbContext 文件可以自动生成。但是你可以在一个完整的类中使用 try/catch 例程,如果它没有生成的话。我有。
  • 使用 CodeFirst 时,显然不会生成 DbContext。但是,当您使用设计器时,会生成 DbContext 和 Entity 类,并且必须使用部分类覆盖。
【解决方案3】:

我将理查兹的答案转换为扩展方法:

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

【讨论】:

    【解决方案4】:

    我最近也被这个惹恼了。我通过在 Seed 方法的 Configuration 类中放置一个包装函数来修复它,并将对 SaveChanges 的调用替换为对我的函数的调用。此函数将简单地枚举 EntityValidationErrors 集合中的错误,并在 Exception 消息列出各个问题时重新引发异常。这会使输出显示在 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() 的调用即可。

    【讨论】:

    • 理查德,终于!有想法的人。一旦我尝试过,我会回到这个问题。
    • 这真的有助于追查讨厌的东西 :)
    • 我使用了这种技术,但在上下文中使用了 savechanges 覆盖。 public override int SaveChanges() 在上下文中。
    • 使用部分类更有效,正如我在下面回答的那样。
    • 如果您在种子方法中执行 UserManager 操作,那么此更改将不会在输出中包含验证错误,您将需要覆盖 DBContext SaveChanges、SaveChangesAsync 和 SaveChangesAsync(CT) 方法@jwize 回答。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      Richard 感谢您让我走上了正确的道路(遇到了同样的问题),下面是一个没有包装器的替代方案,这在迁移配置种子方法中对我有用:

       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
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-05-23
        • 1970-01-01
        • 2013-06-02
        • 2017-10-23
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多