C# 如何放弃对EF Core中上下文的更改
我有一个json格式的“扁平化”对象的巨大列表,以及一个有点复杂的关系数据库模式(大约有20个表对应于扁平化对象)。我正在尝试在新的关系数据库中自动插入这些扁平对象:C# 如何放弃对EF Core中上下文的更改,c#,.net,entity-framework,entity-framework-core,C#,.net,Entity Framework,Entity Framework Core,我有一个json格式的“扁平化”对象的巨大列表,以及一个有点复杂的关系数据库模式(大约有20个表对应于扁平化对象)。我正在尝试在新的关系数据库中自动插入这些扁平对象: foreach (var flattenedObject in flattenedObjects) { _repository.Insert(flattenedObject).Wait(); //some time logging, etc } Insert()方法为不同表中的许多相关对象调用addRangeAy
foreach (var flattenedObject in flattenedObjects)
{
_repository.Insert(flattenedObject).Wait();
//some time logging, etc
}
Insert()
方法为不同表中的许多相关对象调用addRangeAync()
和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块中的某个地方发生错误(我尝试插入一个违反复合主键的对象),我的整个上下文对象就会损坏
导致异常的对象仍保留在my DbContext中,并且在不同事务中对AddAsync()
的任何后续调用都会触发新的异常
我尝试为上面的foreach
循环中的每个新对象重新创建DbContext和repo,但即使这样,如果我查询:
_context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged);
我看到我的旧对象仍然在dbContext的新实例中
有没有什么(优雅的)方法可以告诉我的上下文重置所有挂起的更改,以便在发生错误时将其放入catch块?我希望我失败的事务中发生的一切都留在那里,而不是泄漏。下面的代码对我很有用。但是,如果有人发布了一个更干净的解决方案(我仍然希望EF有一些现成的东西),我会接受它
private void ResetContextState() => _context.ChangeTracker.Entries()
.Where(e => e.Entity != null).ToList()
.ForEach(e => e.State = EntityState.Detached);
在分离之前,您是否应该在.where(e=>e.Entity!=null&&e.state==EntityState.Added)中包含以下条件这对于我当前的插入导致问题的场景是正确的。但是,有些人在更新时可能会遇到类似的问题,因此,如果其他人遇到此类问题,我会将此答案保留为“复制+粘贴”。将上下文中存在的每个实体与context.Reload()相等,当下次使用上下文时。这将对数据库产生巨大的影响。因为这与创建上下文对象againcontext是一样的。重载()正是我在这个问题中寻找的。尽管如此,它似乎并没有成为标准EF核心包的选项。在EF核心3.1上,我找不到一个重新加载选项本身;但是,在分离ChangeTracker中的所有条目之后——使用上述代码——我可以调用context.SaveChanges()来有效地重置它(解析并丢弃所有分离的条目,将更改计数保留为零,并有效地保存零内容,因此不会对数据库产生影响)。然后继续使用上下文。