繁体   English   中英

无法跟踪实体类型的实例,因为已跟踪另一个具有与 {'Id'} 相同键值对的实例

[英]The instance of the entity type cannot be tracked because another instance with the same key value pair for{'Id'} is already being tracked

我知道这个问题已经被问过好几次,而且大多数人都直接建议解决问题中提出的代码片段,但我真的很想知道这个错误背后的核心原因,因为我们在什么情况下会得到这个错误? 我在许多问题中看到人们给出了可以解决问题的不同答案,但我仍然没有找到导致此错误的确切原因。 我读到这是由于 EF Core 的跟踪行为造成的,但究竟是什么行为导致了这个问题?

一些小的代码示例将不胜感激。 谢谢。

本质上,原因在错误消息中。

当您使用 EF 从数据库下载某些内容时,除非您告诉它不要这样做,否则它会跟踪它下载的实体。 无论你对你得到的实体做什么,EF 也会记住它。 这不是唯一的原因,但一个非常明显的原因是,当需要保存更改时,它会让生活变得更加轻松:

var u = db.Users.FirstOrDefault(x => x.Name == "John");
u.Name = "Jim";
db.SaveChanges();

如果 EF 从字面上只是下载了数据,创建了一个User并将其移交并且没有保留其中的任何 memory,那么SaveChanges将不起作用; 它必须看起来像

db.SaveChanges(u);

也就是说,您必须返还更改后的数据。 如果您想使用乐观并发,这也会带来更多的复杂性,因为这通常通过将 in-db 值与最初下载的值进行比较来了解其他人是否在您拥有 object 的时间编辑了数据库.

乐观的保存可能看起来像:

UPDATE user SET name = 'Jim' WHERE id = 123 and name = 'John'

我们知道用户的原始名称(“John”)包含在更新查询中。 如果没有其他人更改用户名,那么很好,更新将成功,因为 WHERE 子句将为真。 如果有人在我们之前重命名了这个用户,那么更新失败(更新 0 行),我们可以处理它。

如果 EF 丢失了旧名称的所有 memory,我们将无法执行任何操作; User object 只有一个简单的Name字符串属性,在我们用"Jim"覆盖它之前不记得"John" 。当需要将其更新回数据库时,从来不知道用户的原始名称是什么

可以公平地说,在 EF 上下文的背景中确实有很多聪明的东西,远远超出了我们看到的东西(即“用户对象”)并记住它看到的对象和关于它们的数据,它们的原始值、当前值、是否添加/更新/删除它们等对于能够有效地 function 至关重要


问题来了,如果你做一些事情,比如用与 EF 已知的主键相同的主键创建另一个全新的User实体,并尝试将它附加到 EF 的 object 商店:

var u1 = db.Users.FirstOrDefault(x => x.Name == "John"); //EF now knows user 123
...
var u2 = new User { Id = 123, Name = "Mary"}
db.Users.Add(u2); //EF already knows user 123; John

如果 EF 知道 ID 为 123 的两个用户,则它无法确定哪个记录是权威的真实记录,因此它拒绝开始记住另一个具有它已知 ID 的不同用户。 上面代码中两个用户是memory中不同地方的不同对象,他们共享同一个ID。 这无法映射回数据库


可能还应该指出的是,如果您已经告诉 EF ID 是由数据库生成的,那么在执行添加时为 ID 输入的内容根本无关紧要:EF 将知道它是一个添加的实体,它将保存时它的 ID 被数据库覆盖,这样如果您的“临时”与现有实例冲突,您就不会收到“另一个具有相同 ID 的实例”错误

好吧,我已经调试了这部分EF Core。 ChangeTracker 中至少有两次检查实体是否存在。

  1. 通过实体引用查找条目,如果找到 - 一切正常。
  2. 按实体的主键查找条目,如果找到 - 你有这个例外。

如果通过了第二次检查,则附加实体将在两个词典中注册(如果您有多个键,它将是额外的词典以通过键查找条目)。

这是一个简化的解释,但它解释了为什么最好先查看已跟踪的实体,然后决定使用哪个条目来避免此类异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM