【问题标题】:Entity framework Core - The instance of entity type cannot be tracked because another instance with the key value is already being tracked实体框架核心 - 无法跟踪实体类型的实例,因为已在跟踪具有键值的另一个实例
【发布时间】:2020-01-30 08:34:18
【问题描述】:

尝试在我的数据库上下文中建立多对多关系,在播种数据时出现以下错误:

无法跟踪实体类型“文件夹”的实例,因为 另一个具有键值“{Id: folder001}”的实例是 已经被追踪。附加现有实体时,请确保 只附加了一个具有给定键值的实体实例。

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);
    builder.Entity<UserFolder>(userFolder =>
    {
        userFolder.HasKey(ud => new { ud.UserId, ud.FolderId });

        userFolder.HasOne(uf => uf.Folder)
            .WithMany(f => f.Users)
            .HasForeignKey(uf => uf.FolderId)
            .IsRequired();

        userFolder.HasOne(uf => uf.User)
            .WithMany(f => f.Folders)
            .HasForeignKey(uf => uf.UserId)
            .IsRequired();
    });
}

_

public class Folder
{

    public string Id { get; set; }
    public string FolderName { get; set; }

    public virtual ICollection<UserFolder> Users { get; set; }
}

_

public class User
{

    public string Id { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<UserFolder> Folders { get; set; }
}

_

public class UserFolder
{
    public string UserId { get; set; }
    public virtual User User { get; set; }

    public string FolderId { get; set; }
    public virtual Folder Folder { get; set; }

}

搜索此错误结果主要是关于需要使用 Scoped 而不是 Singleton 来注册服务的答案,但在这里我是这样配置我的服务的:services.AddDbContext&lt;DataContext&gt;,也有一些答案说需要添加 @ 987654326@.

那么我怎样才能摆脱这个错误呢?

【问题讨论】:

  • 播种数据的代码是什么?
  • 播种数据适用于 Role 和 UserRole,为了简洁起见,我不想在这个问题中添加太多内容,而且我已经检查了此类的数据以确保那里没有任何问题
  • 为了清楚起见,重要的是要意识到在实体框架术语中,这不是多对多关系,而是三个实体之间有两个一对多关系。 EF 中的多对多关系是交叉表对开发人员不明确可见的关系(EF 在您不知道的情况下在后台执行此操作)。 EF Core 实际上并不支持多对多关系,这会妨碍您在线查找信息和解决方案的能力。

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


【解决方案1】:

您实际上并没有发布与错误相关的代码,但我可以解释错误的原因。

Entity Framework 有一个 changetracker,这意味着 db 上下文有一种它所知道的实体的“秘密字典”,它像缓存一样使用它来减少数据库调用并跟踪你做了什么和不做什么不要改变这些实体。这些实体使用它们的主键在更改跟踪器中存储和引用。

Entity Framework 只能存储 一个 给定类型和给定 PK 值的对象。它无法跟踪具有相同值的两个不同对象。

把它想象成一个字典,它只能为给定的键值存储一个值。字典很乐意用另一个值覆盖一个值,但 EF 拒绝这样做,因为这很可能导致意外行为并且难以解决错误。

以下代码将引发与您遇到的相同的错误:

using(var db = new MyContext())
{
    Foo foo1 = new Foo() { Id = 123 };
    Foo foo2 = new Foo() { Id = 123 }; // different object in memory, same PK identifier

    db.Foos.Attach(foo1);
    db.Foos.Attach(foo2); // exception! 
}

我不能告诉你这个错误是在你的代码中引起的,因为你没有发布可能发生这种情况的代码。

【讨论】:

  • 你指出了正确的方向,我发现种子方法是从项目中的两个不同地方调用的,所以谢谢。
  • 要查看“秘密词典”,请关注context.ChangeTracker.DebugView.ShortView,您将看到所有被跟踪的实体。对调试这个错误很有帮助。
猜你喜欢
  • 2023-01-03
  • 1970-01-01
  • 2022-01-02
  • 2020-01-31
  • 1970-01-01
  • 2019-12-29
  • 1970-01-01
  • 2018-06-20
相关资源
最近更新 更多