【发布时间】:2017-08-10 15:13:30
【问题描述】:
我有大量 json 格式的“扁平化”对象列表,以及一个有点复杂的关系数据库模式(大约 20 个表对应于扁平化对象)。我正在尝试在我的新关系数据库中自动插入这些扁平对象:
foreach (var flattenedObject in flattenedObjects)
{
_repository.Insert(flattenedObject).Wait();
//some time logging, etc
}
Insert() 方法针对不同表中的多个相关对象调用AddRangeAsync() 和AddAsync()。
由于展平对象是遗留的,我想说其中大约 0.001% 的对象格式不正确并且会违反数据库约束 - 例如尝试在其中一个表中插入重复的复合主键。
我预计会出现这些罕见的错误,因此我的想法是 - 将整个 Insert() 操作包装在一个事务中 - 如果任何部分操作无效,请不要插入任何内容并记录错误,这样我就可以修改在重试之前手动展平对象。因此我的代码看起来有点类似于:
public async Task Insert(FlattenedObject fo)
{
using (var transaction = _context.Database.BeginTransaction())
{
try
{
//magical code that calls AddAsync for multiple tables
}
catch (Exception ex)
{
transaction.Rollback()
//logging
}
}
}
但是,如果在我的 try 块中某处发生错误(我尝试插入违反复合主键的对象),我的整个上下文对象就会损坏。
导致异常的对象仍保留在我的 DbContext 中,并且在不同事务中对 AddAsync() 的任何后续调用都会触发新异常。
我尝试为上面foreach 循环中的每个新对象重新创建我的 DbContext 和 repo - 但即便如此,如果我查询:
_context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged);
我看到我的旧对象仍在 dbContext 的新实例中。
是否有任何(优雅的)方法可以告诉我的上下文重置所有待处理的更改 - 这样我就可以在发生错误时将其放入 catch 块中?我希望我失败的交易中发生的所有事情都留在那里而不是泄漏。
【问题讨论】:
标签: c# .net entity-framework entity-framework-core