2017-03-19 214 views
1

变化方面,我有一个巨大的JSON格式的“扁平化”的对象列表,(对应于扁平物体约20桌)计算一个比较复杂的关系数据库架构。我想我的新关系数据库的扁平物体插入自动:如何丢弃EF核心

foreach (var flattenedObject in flattenedObjects) 
{ 
    _repository.Insert(flattenedObject).Wait(); 
    //some time logging, etc 
} 

Insert()方法为许多不同表中相关对象的调用AddRangeAsync()AddAsync()

由于扁平对象是传统的,我会说他们的约0.001%是畸形的,将违反DB的约束 - 例如试图插入在其中一个表的重复复合主键。

我希望这些罕见的错误,因此,我的想法是 - 包装在一个事务中的整体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()触发一个新的异常。

我试图重建我的DbContext和回购在foreach循环上述每一个新的对象 - 但即便如此,如果我查询:

_context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged); 

我看到我的旧的对象仍然是的DbContext的新实例。

是否有任何(优雅的)的方式来告诉我的情况下,可以将所有挂起的更改 - 这样我就可以把它放在每当出现错误catch块?我希望在失败的事务中发生的所有事情都留在那里,不会泄漏。

回答

0

下面的代码适合我。但是,如果有人发布了一个更清洁的解决方案(我仍然期望EF有一些开箱即用的功能),我会接受它。

private void ResetContextState() => _context.ChangeTracker.Entries() 
    .Where(e => e.Entity != null).ToList() 
    .ForEach(e => e.State = EntityState.Detached); 
+0

不应该包括你在下面的条件。凡(E => e.Entity!= NULL && e.state == EntityState.Added)分离 – CPR43

+0

在此之前,将在那里插入引起了我目前的情况是真实的麻烦。然而,有人可能会与更新有类似的问题,所以我会留下这个答案,因为它是复制+粘贴,如果别人面临这样的问题。 – nikovn

+0

代码有问题吗?潜在的错误可能? 为什么downvote? – nikovn