EF Core 2.0:如何在对象图中发现导致插入操作错误的确切对象?
EF Core 2.0: How to discover the exact object, in object graph, causing error in a insert operation?
我有一个复杂的大对象图,我想使用 DbContext 和 SaveChanges 方法将其插入数据库。
这个对象是解析一个 40k 行的文本文件(大约 3MB 的数据)的结果。此对象中的某些集合有数千项。
我能够正确解析文件并将其添加到上下文中,以便它可以开始跟踪对象。但是当我尝试 SaveChanges 时,它说:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: String or binary data would be truncated.
我想知道是否有一种聪明有效的方法来发现导致问题的对象。似乎 varchar 字段太少,无法存储数据。但是要手动检查很多表和字段。
我想以某种方式得到更具体的错误。我已经配置了 ILoggerProvider 并在我的 dbContext 中添加了 EnableSensitiveDataLogging 选项,以便能够查看正在生成哪些 sql 查询。我什至添加了 MiniProfiler 以便能够查看参数值,因为它们不存在于 dbContext 生成的日志中。
在网上某处阅读时,我发现在 EF6 中,在将 sql 传递到要执行的数据库之前会进行一些验证。但似乎在 EF Core 中这不再可用。那么我该如何解决呢?
经过一些研究,我发现解决此问题的唯一方法是通过覆盖 dbContext 的 SaveChanges 方法来实现一些验证。我合并了这两种方法来构建我的方法:
Implementing Missing Features in Entity Framework Core - Part 3
结果是……
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 重载,因为它们会调用这两个重载。
错误告诉您,您向字段写入的字符数超出了它的容量。
例如,当您将给定字段创建为 NVARCHAR(4) 或 CHAR(4) 并向其写入 'hello' 时,会抛出此错误。
所以您可以简单地检查您读入的值的长度,以找出导致您出现问题的值。至少有一个字段太长了。
我有一个复杂的大对象图,我想使用 DbContext 和 SaveChanges 方法将其插入数据库。
这个对象是解析一个 40k 行的文本文件(大约 3MB 的数据)的结果。此对象中的某些集合有数千项。
我能够正确解析文件并将其添加到上下文中,以便它可以开始跟踪对象。但是当我尝试 SaveChanges 时,它说:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: String or binary data would be truncated.
我想知道是否有一种聪明有效的方法来发现导致问题的对象。似乎 varchar 字段太少,无法存储数据。但是要手动检查很多表和字段。
我想以某种方式得到更具体的错误。我已经配置了 ILoggerProvider 并在我的 dbContext 中添加了 EnableSensitiveDataLogging 选项,以便能够查看正在生成哪些 sql 查询。我什至添加了 MiniProfiler 以便能够查看参数值,因为它们不存在于 dbContext 生成的日志中。
在网上某处阅读时,我发现在 EF6 中,在将 sql 传递到要执行的数据库之前会进行一些验证。但似乎在 EF Core 中这不再可用。那么我该如何解决呢?
经过一些研究,我发现解决此问题的唯一方法是通过覆盖 dbContext 的 SaveChanges 方法来实现一些验证。我合并了这两种方法来构建我的方法:
Implementing Missing Features in Entity Framework Core - Part 3
结果是……
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 重载,因为它们会调用这两个重载。
错误告诉您,您向字段写入的字符数超出了它的容量。 例如,当您将给定字段创建为 NVARCHAR(4) 或 CHAR(4) 并向其写入 'hello' 时,会抛出此错误。
所以您可以简单地检查您读入的值的长度,以找出导致您出现问题的值。至少有一个字段太长了。