如何还原已分离实体的更改

时间:2016-03-12 11:37:19

标签: c# .net entity-framework

以下是该计划的流程:

  1. 获取实体列表并使用它们。这将断开/分离所有实体与上下文。
  2. 对其中一个实体进行更改并保存。我正从上下文加载实体,并将分离实体的更改(标量属性和关系)应用于新加载的实体。
  3. 我有一个功能,用户可以恢复对断开连接的实体所做的所有更改。这是我正在使用的代码:

        public async Task RevertChanges()
    {
        using (var db = new TwinTailDb())
        {
            //Fansubs.Clear();
    
            if (db.Entry(this).State == EntityState.Detached && Id != 0)
            {
                db.ArchiveEntries.Attach(this);
                await db.Entry(this).ReloadAsync();
            }
    
            //await db.Entry(this).Collection(a => a.Fansubs).LoadAsync();
        }
    }
    
  4. 但是,当我附加分离的实体时,它会抛出此异常:

      

    附加信息:附加“TwinTail.Entities.ArchiveEntry”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图表,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

    请注意,上下文会自动处理,因为我使用使用语句。

    我不确定为什么即使主键发生冲突,因为我甚至没有加载另一个实体,因为之前的上下文已经被处理掉了。

    此外,如果我跳过第2步,我保存实体中的所有更改,它不会抛出异常。我不禁想到它仍在被追踪。

    修改 这是当我跳过附件时发生的事情,证明实体真的是分离的。

      

    附加信息:无法为“ArchiveEntry”类型的实体调用成员“ReloadAsync”,因为该实体在上下文中不存在。要向上下文添加实体,请调用DbSet的Add或Attach方法。

    说真的,发生了什么:(

2 个答案:

答案 0 :(得分:0)

涉及上下文的实体的某些操作可能会将状态更改为Attached。在将实体传递给上下文中的方法时,可能发生。尝试在实体状态更改时放置具有条件的断点,并确保在实际调用attach之前实体不会附加,这是其他操作的副作用。如果是这种情况,那么您试图附加已经附加的实体,这应该会导致异常。

答案 1 :(得分:0)

回答我自己的问题。

主要问题是我处理上下文生命周期的方式是错误的。此外,附加从另一个上下文加载的实体肯定会抛出错误。在上下文中加载的实体只应在该上下文中使用。

我的背景太短暂了。我将调整其生命周期,以便每个事务(数据库进程)都有一个上下文。

这是一篇关于如何解决/设计您的架构的非常详细的文章:http://mehdi.me/ambient-dbcontext-in-ef6/

修复架构后,可以通过调用:

简单地重新加载/恢复实体
DbContext.Entry(entity).Reload();