EF Core 2.0:如何在对象图中发现确切的对象,导致插入操作出错?

时间:2017-08-22 19:37:47

标签: entity-framework-core asp.net-core-2.0

我有一个复杂的大对象图,我希望使用DbContext和SaveChanges方法在数据库中插入。

此对象是使用40k行(大约3MB数据)解析文本文件的结果。此对象中的某些集合包含数千个项目。

我能够正确解析文件并将其添加到上下文中,以便它可以开始跟踪对象。但是当我尝试SaveChanges时,它说:

  

Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时发生错误。有关详细信息,请参阅内部异常---> System.Data.SqlClient.SqlException:字符串或二进制数据将被截断。

我想知道是否有一种智能且有效的方法来发现哪个对象导致了问题。似乎varchar字段太小而无法存储数据。但是需要手动检查很多表格和字段。

我想以某种方式得到更具体的错误。我已经配置了 ILoggerProvider 并在我的dbContext中添加了 EnableSensitiveDataLogging 选项,以便能够查看正在生成哪些SQL查询。我甚至添加了 MiniProfiler 以查看参数值,因为它们不存在于dbContext生成的日志中。

在Web上的某处读取,我发现在EF6中,在将sql传递给要执行的数据库之前会发生一些验证。但似乎在EF Core中不再可用了。那我怎么解决这个问题呢?

2 个答案:

答案 0 :(得分:0)

经过一些研究,我发现解决这个问题的唯一方法是通过重写dbContext的SaveChanges方法来实现一些验证。我已经将这两种方法合并在一起构建我的方法:

Implementing Missing Features in Entity Framework Core - Part 3

Validation in EF Core

结果是......

<强> ApplicationDbContext.cs

    public override int SaveChanges(bool acceptAllChangesOnSuccess)
    {
        ValidateEntities();

        return base.SaveChanges(acceptAllChangesOnSuccess);
    }

    public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
    {
        ValidateEntities();

        return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    }

    private void ValidateEntities()
    {
        var serviceProvider = this.GetService<IServiceProvider>();
        var items = new Dictionary<object, object>();

        var entities = from entry in ChangeTracker.Entries()
                       where entry.State == EntityState.Added || entry.State == EntityState.Modified
                       select entry.Entity;

        foreach (var entity in entities)
        {
            var context = new ValidationContext(entity, serviceProvider, items);
            var results = new List<ValidationResult>();

            if (Validator.TryValidateObject(entity, context, results, true)) continue;

            foreach (var result in results)
            {
                if (result == ValidationResult.Success) continue;

                var errorMessage = $"{entity.GetType().Name}: {result.ErrorMessage}";
                throw new ValidationException(errorMessage);
            }
        }
    }

请注意,没有必要覆盖其他SaveChanges重载,因为他们会调用这两个。

答案 1 :(得分:0)

错误告诉您,您在字段中写入的字符多于它可以容纳的字符数。 例如,当您将给定字段创建为NVARCHAR(4)或CHAR(4)并向其写入“hello”时,将抛出此错误。

因此,您只需检查所读取值的长度即可找到导致问题的值。至少对于一个领域来说太长了。