我正在寻找插入Entity Framework的最快方法.
我问这个是因为你有一个活跃的TransactionScope并且插入很大(4000+).它可能持续超过10分钟(事务的默认超时),这将导致事务不完整.
我有一个巨大的json格式的"扁平"对象列表,以及一个有点复杂的关系数据库模式(大约有20个表对应于展平对象).我正在尝试在新的关系数据库中自动插入那些展平的对象:
foreach (var flattenedObject in flattenedObjects)
{
_repository.Insert(flattenedObject).Wait();
//some time logging, etc
}
Run Code Online (Sandbox Code Playgroud)
该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
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我的try块中某处发生错误(我尝试插入违反复合主键的对象),我的整个上下文对象就会变坏.
导致异常的对象仍然保留在我的DbContext中,并且AddAsync()在另一个事务中的任何后续调用都会触发新的异常.
我尝试为foreach上面的循环中的每个新对象重新创建我的DbContext和repo - 但即使这样,如果我查询:
_context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged);
Run Code Online (Sandbox Code Playgroud)
我看到我的旧对象仍然在dbContext的新实例中.
是否有任何(优雅)方式告诉我的上下文重置所有挂起的更改 - 以便每当发生错误时我都可以将它放在catch块中?我希望在失败的交易中发生的一切都留在那里而不是泄漏.