【问题标题】:Entity Framework Core DbUpdateException detailed informationEntity Framework Core DbUpdateException 详细信息
【发布时间】:2017-03-14 22:16:40
【问题描述】:

我刚刚在我的完整 .net 4.5.2 项目中开始使用 EF Core,并且正在尝试进行集成测试以验证我可以插入一个新学生。

问题是,我希望能够从抛出的异常中获得更好的信息,说明为什么它没有插入到数据库中。

这是我的集成测试代码:

    [Fact]
    public void save_the_new_student_to_the_database()
    {
        var fixture = new Fixture();
        var optionsBuilder = new DbContextOptionsBuilder<TestDbContext>();
        //optionsBuilder.UseInMemoryDatabase();
        optionsBuilder.UseSqlServer("Server = (localdb)\\mssqllocaldb; Database = afmil_Test_next; Trusted_Connection = True; "
                );

        using (var context = new TestDbContext(optionsBuilder.Options))
        {
            var command = fixture.Create<PostRegisterStudentCommand>();
            var handler = new PostRegisterStudentCommandHandler(context);

            try
            {
                handler.Handle(command);
            }
            catch (DbUpdateException e)
            {
                var sb = new StringBuilder();
                sb.AppendLine($"DbUpdateException error details - {e?.InnerException?.InnerException?.Message}");

                foreach (var eve in e.Entries)
                {
                    sb.AppendLine($"Entity of type {eve.Entity.GetType().Name} in state {eve.State} could not be updated");
                }

                sb.ShouldBeNull();
            }

            var dbStudent = context.Students.FirstOrDefault();
            dbStudent.ShouldNotBeNull();
            dbStudent.User.FirstName.ShouldBe(command.FirstName);
        }

    }

我从 EF 6 stackoverflow answer 获得了异常捕获部分。

我已经搜索了我能想到的所有内容,以找到在 EF Core 中提取实体验证问题(来自 EF6 的 DbEntityValidationException)的示例,但找不到任何似乎有效的内容。

根据this EF Core github issue 的建议,我尝试进行一些注释验证,例如this。但这并没有发现 db 对我的学生对象存在的问题。

【问题讨论】:

标签: c# integration-testing entity-framework-core


【解决方案1】:

事实上,EF7 缺乏在 EF6 中可用的验证。这似乎是一种设计选择,因为在发送模型以保存之前假设验证(并且数据库约束可能用作安全网)。

This article 展示了如何在保存数据之前手动执行验证。但是,请注意,这仅适用于数据注释。我稍作改动的版本如下:

public void Validate()
{
    var entities = ChangeTracker.Entries()
        .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified)
        .Select(e => e.Entity);
                   
    foreach (var entity in entities)
    {
        var validationContext = new ValidationContext(entity);
        Validator.ValidateObject(entity, validationContext, validateAllProperties: true);
    }
}

我的建议是有一种方法来处理两种类型的异常(验证和数据库),如下所示:

try
{
    Validate();
    Context.SaveChanges();
}
catch(ValidationException exc)
{
    Logger.LogError(exc, $"{nameof(SaveChanges)} validation exception: {exc?.Message}");
    return false;
}
catch (DbUpdateException exc)
{
    Logger.LogError(exc, $"{nameof(SaveChanges)} db update error: {exc?.InnerException?.Message}");
    return false;
}

【讨论】:

  • 如果您要在之后立即调用 foreach 枚举,则无需在 Validate() 方法中执行 .ToList()。无论如何,它都会解压 IQueryable 并返回结果。您将节省一些时间
猜你喜欢
  • 2020-08-28
  • 2020-01-01
  • 2019-04-30
  • 1970-01-01
  • 2014-11-13
  • 1970-01-01
  • 2018-06-27
  • 2016-11-21
  • 1970-01-01
相关资源
最近更新 更多