【问题标题】:EFcore - multiple untracked instances of same object/entity in a List Property return error about another tracked instanceEFcore - 列表属性中相同对象/实体的多个未跟踪实例返回关于另一个跟踪实例的错误
【发布时间】:2021-12-07 13:54:16
【问题描述】:

我没有找到任何有关此问题的资源,可能是措辞错误的原因。

设置是一个实体Lake,其中包含Fish 的列表。每个Fish 实体还包含一个其类型的实体FishKind。通过一些 API,我得到了一个 Lake 已经包含很多 Fish 的对象。由于某种原因,存在相同种类的鱼 -> 因此我们有多个具有相同 ID 的 FishKind 类的对象/实例。

这里是一些关于 Object Hiracy 的虚拟代码:

class Lake {
    public int LakeId;
    public List<Fish> Fish;
}
class Fish {
    public int FishId;
    public FishKind Kind;
}
class FishKind {
    public int FishKindId;
    FishKind(int id) { FishKindId = id; }
}
// this is how example data from the API could look like - I don't create objects like this in my code. I get them via the API
// The FishKind have the same id/data however a different instances in C#
// The FishKind have valid IDs which are also already in the DB
// only Lake and Fish should be created
var lake = new Lake();
var idOfShark = 29;
lake.Fish.Add(new Fish("Tony", new FishKind(idOfShark)));
lake.Fish.Add(new Fish("Helen", new FishKind(idOfShark)));

进一步说明 - 通过 API 接收的示例数据

{
   "LakeId":0,
   "Fish":[
      {
         "FishId":0,
         "Name":"Tony",
         "Kind":{
            "FishKindId":29
         }
      },
      {
         "FishId":0,
         "Name":"Helen",
         "Kind":{
            "FishKindId":29
         }
      }
   ]
}
  • 当我执行 db.AddAsync(Lake) 时,它会失败,因为我已经将这种鱼添加到数据库中
  • 当我尝试db.Update(Lake) 时,只要我没有两条同种鱼,它就可以工作。如果他们是同一种我得到:The instance of entity type 'FishKind' cannot be tracked because another instance with the key value '{FishKindId: 1}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.'

我想到的一种解决方法是将所有 FishKind 实例替换为已跟踪的对象,但这似乎很复杂,并且像一个 hacky 解决方案。

【问题讨论】:

  • @T.Trassoudaine 我只写了一些最少的代码。确保所有对象都有 ID,否则我无法创建迁移。我编辑了帖子以添加 ID
  • @T.Trassoudaine 我不想创建新的 FishKind。从另一个湖的创建中,这些种类可能已经存在。 (或者在创建新的鱼/湖时在 GUI 中导致我从数据库加载所有种类)
  • @T.Trassoudaine 我不想创建新种类。但是我通过 Rest 获取对象,所以它们不同。上述解决方法是查找所有 FishKinds 并用跟踪的 obj 替换它们
  • 从 API 获取数据的实际代码怎么样,知道为什么要为每个 Fish 创建一个新的 FishKind 实例吗?
  • @T.Trassoudaine 我认为这是因为 asp.net 不知道对象是相同的实体,因此创建相同的对象但不同的实例

标签: c# asp.net-core entity-framework-core .net-6.0


【解决方案1】:

看看你在哪里做的:

lake.Fish.Add(new Fish("Tony", new FishKind(idOfShark)));
                               ^^^^^^^^^^^^^^^^^^^^^^^

不要;您不断地创建与上下文已经知道的现有对象具有相同 ID 的新对象。要么重用实体知道:

var shark = context.FishKinds.Single(fk => fk.FishKindId == 29); //if its local it will be returned, if it's not it will be fetched and remembered 

lake.Fish.Add(new Fish("Tony", shark));
lake.Fish.Add(new Fish("Mary", shark));

或升级您的 Fish 实体,使其具有 FishKindId(或数据库中映射到 FiskKind PK 的列名是否为)int 属性并将其设置为 29 (idOfShark),将 FishKind 实体保留为空。

【讨论】:

  • 这是正确的,但我从不这样做 new FishKind(idOfShark) 这是由 JsonSerializer 完成的
  • 哦,我明白了.. 考虑到 db 实体可能会导致这种情况。我能想到很多方法来解决,最简单的可能是“将 FishKindId 放入 Fish,枚举鱼转移是从 theFish.FishKind.FishKindId 到 theFisjh.FishKindId 并将 theFish.FiskKind 设置为 null
  • (本质上将对象图修复为更改跟踪器可以容忍的内容)。您还可以枚举替换所有 theFish.FishKind = context.FishKinds.Single(fk =&gt; fk.FishKindId == theFish.FishKind.FishKindId) 的鱼
  • 感谢您的回答,我偶然发现了ForeignKey("FishKindId")],我目前正在对其进行测试。我可以更改 API,它只给我 FishKindId 而不是完整对象
  • 对初始评论的错字更正:哦,我明白了.. 考虑到数据库实体可能会导致这种情况。我能想到很多解决方法,最简单的可能是“将FishKindId 放入Fish,枚举lake.Fish 将ID 从lake.Fish.FishKind.FishKindId 转移到lake.Fish.FishKindId 并将lake.Fish.FishKind 设置为null
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-20
  • 2021-11-29
  • 2022-01-02
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
相关资源
最近更新 更多