如何在EF Core中放弃对上下文的更改 [英] How to discard changes to context in EF Core

查看:124
本文介绍了如何在EF Core中放弃对上下文的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个庞大的json格式的扁平化对象列表,以及一个稍微复杂的关系数据库模式(约有20个表对应于扁平化对象)。我正在尝试自动在我的新关系数据库中插入那些展平对象:

I have a huge list of "flattened" objects in json format, and a somewhat complicated relational DB schema (with about 20 tables corresponding to a flattened object). I'm trying to automate the insertions of those flattened objects in my new relational database:

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

Insert()方法调用 AddRangeAsync() AddAsync()

由于展平的对象是旧版,因此我想说其中约0.001%的格式不正确,并且会违反数据库约束-例如,试图在一个表中插入重复的复合主键。

Since the flattened objects are legacy, I'd say about 0.001% of them are malformed and will violate DB constraints - for example trying to insert a duplicate composite primary key in one of the tables.

我期望这些罕见的错误,因此我的想法是-包装整个 Insert() 事务中的操作-如果该操作的任何部分无效,则不要插入任何内容并记录错误,因此我可以在再次尝试之前手动修改展平的对象。因此,我的代码与此类似:

I expect these rare errors, thus my idea is - wrap the whole Insert() operation in a transaction - if any piece of the operation is invalid, just don't insert anything and log the error, so I can modify the flattened object manually before trying again. Thus my code looks somewhat similar to this:

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块中发生错误(我尝试插入违反复合主键的对象),则整个上下文对象变得腐败。

However, if an error occurs somewhere in my try block (I try to insert an object that violates a composite primary key) my whole context object becomes corrupt.

导致异常的对象仍然保留在我的DbContext中,并且随后在不同的 AddAsync()中调用事务触发了一个新的异常。

The object that caused the exception still remains in my DbContext and any following call to AddAsync() in a different transaction triggers a new exception.

我尝试为上述 foreach 循环中的每个新对象重新创建DbContext和存储库-但即使这样我仍然查询:

I tried recreating my DbContext and repo for every new object in the foreach loop above - but even then if I query:

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

我看到我的旧对象仍在dbContext的新实例中。

I see my old object is still in the new instance of dbContext.

是否有任何(优雅的)方式告诉我的上下文重置所有未决的更改-以便在发生错误时将其放入catch块中?我希望失败的事务中发生的所有事情都留在那儿而不泄漏。

Is there any (elegant) way to tell my context to reset all pending changes - so that I can put it in the catch block whenever an error occurs? I want everything that happens within my failed transaction to stay there and not leak.

推荐答案

下面的代码对我有用。但是,如果有人发布了一个更清洁的解决方案(我仍然希望EF提供一些开箱即用的东西),我会接受的。

The code below worked for me. However, if someone posts a cleaner solution (I still expect there to be something out of the box with EF) I will accept it.

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

这篇关于如何在EF Core中放弃对上下文的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆