重新连接一个分离的实体会引发异常 [英] Reattaching a detached entity throws an exception

查看:86
本文介绍了重新连接一个分离的实体会引发异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Entity Framework 6(使用生成的模型和DbContext)作为我的项目。我在我的程序中使用的架构是数据访问层是从应用程序中抽象出来的。这意味着我的实体将主要处于分离状态。



似乎重新连接任何以前连接的实体似乎是不可能的(或者我没有正确地执行)。 >

我已经单独测试了一个案例,并且能够将问题缩小。以下是步骤。


  1. 从上下文获取实体并处理上下文。这将分离实体。

      public async任务< ArchiveEntry> GetEntry(string api,string id)
    {
    //为了简单起见省略了一些代码
    ArchiveEntry条目;

    使用(var db = new TwinTailDb())
    {
    entry = await db.ArchiveEntries.Where(a => a.Id == id).SingleOrDefaultAsync );
    }

    返回条目;
    }


  2. 保存实体,无论是否更改。 p>

      public async任务保存()
    {
    //为了简单起见省略了一些代码
    using var db = new TwinTailDb())
    {
    db.ArchiveEntries.AddOrUpdate(a => a.Id,this);
    等待db.SaveChangesAsync();
    }
    }


  3. 最后,重新连接分离的实体。 / p>

      public async任务RevertChanges()
    {
    using(var db = new TwinTailDb())
    {
    if(db.Entry(this).State == EntityState.Detached&& Id!= 0)
    {
    db.ArchiveEntries.Attach(this);
    //等待db.Entry(this).ReloadAsync(); //评论自从这是不相关的
    }
    }
    }


  4. 然后我运行这个函数来使用上面的代码。

      public async Task Test()
    {
    ArchiveEntry entry = await ArchiveService.GetEntry(null,7);
    await entry.Save();
    等待输入.RevertChanges();
    }


然后它抛出这个错误:


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


这是一个重点。如果我跳过步骤2 ,它不会抛出异常。



我的猜测是实体被修改并保存在不同的上下文中。如果跳过步骤2,实体保持不变,因此重新安装它不会造成问题(只是猜测)。但是,该实体已经处于分离的状态,所以这应该是无关紧要的。



另一点, ChangeTracker 在这些步骤中不包含任何内容。另外,如果我在分离的实体上执行任何上下文操作,它会抛出一个异常,指出它应该首先被附加。我也注意到,内部的_entitywrapper仍然引用了旧的上下文。



所以,最后,这里的问题。我如何正确地重新连接实体,为什么会发生这种异常。



我在另一个问题中提出了类似的内容(如何恢复分离的实体上的更改),但觉得我需要发布一个新的实体,因为这是更通用的。

解决方案


我在程序中使用的架构是数据访问层被抽象应用程序。


看起来您正在 ArchiveEntry 中实现这些方法课本身这不是一个抽象的数据访问层,并且传递实体到许多这样的短命的上下文会让你陷入麻烦。



而不是给自己的实体类用于管理持久性问题的方法,您应该将该代码放置在与实体分离的类中,并确保一旦实体连接到上下文,则会继续使用相同的上下文,直到它被处理为止。一旦上下文处理完毕,如果您想对该实体执行另一个操作,那么在尝试执行任何(附加)事情之前,您应该从新的上下文中检索。


I'm using Entity Framework 6 (using generated models and DbContext) for my project. The architecture I'm using in my program is that the data access layer is abstracted from the application. This means my entities will mostly stay in detached state.

It seems that reattaching any previously connected entities seems impossible (or I'm not doing it properly).

I've tested a case in isolation and was able to narrow the problem down. Here are the steps.

  1. Get the entity from the context and dispose the context. This detaches the entity.

    public async Task<ArchiveEntry> GetEntry(string api, string id)
    {
        // Omitted some code for simplicity
        ArchiveEntry entry;
    
        using (var db = new TwinTailDb())
        {
            entry = await db.ArchiveEntries.Where(a => a.Id == id).SingleOrDefaultAsync();
        }
    
        return entry;
    }
    

  2. Save the entity regardless if it was changed or not.

    public async Task Save()
    {
        // Omitted some code for simplicity
        using (var db = new TwinTailDb())
        {
            db.ArchiveEntries.AddOrUpdate(a => a.Id, this);
            await db.SaveChangesAsync();
        }
    }
    

  3. Finally, reattach the detached entity.

    public async Task RevertChanges()
    {
        using (var db = new TwinTailDb())
        {
            if (db.Entry(this).State == EntityState.Detached && Id != 0)
            {
                db.ArchiveEntries.Attach(this);
                //await db.Entry(this).ReloadAsync(); // Commented since this is irrelevant
            }
        }
    }
    

  4. Then I run this function to use the code above.

    public async Task Test()
    {
        ArchiveEntry entry = await ArchiveService.GetEntry(null, "7");
        await entry.Save();
        await entry.RevertChanges();
    }
    

Then it throws this error:

Attaching an entity of type 'TwinTail.Entities.ArchiveEntry' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

Here's an important point. If I skip step 2, it doesn't throw an exception.

My speculation is that the entity was modified and saved in a different context. If step 2 was skipped, the entity remains unchanged so reattaching it doesn't pose a problem (just guessing). However, this entity is already in a detached state so this should be irrelevant.

Another point, the ChangeTracker doesn't contain anything during these steps. Also, if I perform any context operation on the detached entity, it throws an exception saying that it should be attached first. I've also noticed that the internal _entitywrapper still has a reference to the old context.

So, finally, here's the question. How do I properly reattach an entity and why does this exception happen.

I've asked something similar in a different question (How to revert changes on detached entities) but felt that I need to post a new one since this is more general.

解决方案

The architecture I'm using in my program is that the data access layer is abstracted from the application.

It looks like you are implementing these methods on the ArchiveEntry class itself. That is not an abstracted data access layer, and passing entities around to many short-lived contexts like this will get you into trouble.

Instead of giving the entity classes their own methods for managing persistence concerns, you should put that code into a class separate from the entity, and make sure that once an entity gets attached to a context, you keep using that same context until it gets disposed. Once the context is disposed, if you want to do another operation on the entity, you should retrieve it from a new context before trying to do any (attached) things with it.

这篇关于重新连接一个分离的实体会引发异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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