无法跟踪实体类型的实例,因为已经跟踪了另一个具有相同键值的实例

何为EntityState,如何解决Attach出现的跟踪问题

EntityState
之前使用EF,我们都是通过调用SaveChanges方法把增加/修改/删除的数据提交到数据库,但是上下文是如何知道实体对象是增加、修改还是删除呢?答案是通过EntityState枚举来判断的,我们看一个方法:

/// /// 查看实体状态
        /// private static void GetOneEntityToSeeEntityState()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var destination = context.Destinations.Find(4);
                EntityState stateBefore = context.Entry(destination).State;
                Console.WriteLine(stateBefore);
            }
        }

注:使用EntityState需添加引用system.data
跑下程序,输出结果为:Unchanged。从英文意思我们已经猜到一二:取出来的数据是Unchanged,那么添加、修改、删除自然也就是Added、Modified、Deleted了。我们在EntityState上按F12定位到其定义看看:

的确,当调用SaveChanges方法的时候,EF会根据EntityState这个枚举检测到实体的状态,然后执行相应的增/删/改操作。它们的具体意思分别为:

  • Detached:对象存在,但未由对象服务跟踪。在创建实体之后、但将其添加到对象上下文之前,该实体处于此状态;
  • Unchanged:自对象加载到上下文中后,或自上次调用 System.Data.Objects.ObjectContext.SaveChanges() 方法后,此对象尚未经过修改;
  • Added:对象已添加到对象上下文,但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法;
  • Deleted:使用 System.Data.Objects.ObjectContext.DeleteObject(System.Object) 方法从对象上下文中删除了对象;
  • Modified:对象已更改,但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法。

跟踪问题
假设我们从数据库取出一个product对象并且new了一个和该数据库内product对象具有相同ID的product对象,
那么当我们修改完new的对象想要使用attach时就会出现报错:
*

无法跟踪实体类型的实例,因为已经跟踪了另一个具有相同键值的实例

那么这里是什么情况呢?
其实是因为取出的对象此时正在被EF跟踪,而我们想要attach的对象和该取出的对象具有相同的ID,此时就会出现EF无法使用attach的问题
那么如何解决呢?
正如上文所说,实体有很多状态,那么我们只需要将被取出的对象不再被跟踪即可。

db.Entry(entityFromDB).State = entityState.Detached

之后即可直接attach

更多.NET知识可以在我的笔记中学习:
ASP.NET Core RESTful风格学习总结(五万字持续更新)

你可能感兴趣的:(问题原理与解决,c#)