You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core中Book关联Author时的实体跟踪问题求助(NUnit测试)

解答你的EF Core关联与跟踪问题

让我逐个拆解你遇到的问题,帮你理清EF Core的实体跟踪和关联逻辑:

1. 添加Book时,新Author是否会自动入库?

首先纠正一个小细节:你的Book类里的Author是单个实体(不是集合),所以代码里应该是book.Author = newAuthor而不是book.Author.Add(newAuthor)——后者是集合导航属性的写法,比如Book包含List<Author>时才适用。

回到核心问题:如果newAuthor是全新实体(AuthorId为0,假设是自增主键),当你执行dbcontext.Book.Add(book)并调用SaveChanges()时,EF Core默认会自动级联添加关联的新Author到数据库,不需要单独执行dbcontext.Author.Add(newAuthor)。

但你必须手动Add Author才生效的情况,大概率是这两个原因之一:

  • 你的AuthorId不是自增主键,而是手动赋值了一个数据库中不存在的ID,EF Core会认为这个Author是已存在的实体,尝试关联而非插入;
  • 实体关系配置有误,比如没有正确设置外键,或者关闭了级联添加的行为。

2. 错误:“Attempted to update or delete an entity that does not exist in the store”

这个错误的本质是:EF Core认为你要关联的Author是已经存在于数据库中的实体(比如AuthorId有非零值),但实际数据库里并没有这个ID的记录。当你保存Book时,EF Core尝试验证这个关联的Author存在,或者尝试更新它,结果找不到对应记录就报错了。

你添加dbcontext.Author.Add(author)后错误消失,是因为手动告诉EF Core:这个Author是新实体,需要插入到数据库,而非关联已存在的记录。

3. 错误:“The instance of entity type 'Author' cannot be tracked...”

这是EF Core的实体跟踪冲突问题,原因很明确:你的[SetUp]方法已经向上下文添加了一个Author实体(此时上下文正在跟踪这个实体,记录了它的AuthorId),而在测试方法里,你又创建了一个相同AuthorId的Author实例,或者从其他地方获取了同一个ID的实体并尝试关联到Book——EF Core不允许同一个上下文同时跟踪两个具有相同主键的实体。

解决方法有这几种:

  • 直接使用SetUp里的Author实例:不要重新创建,而是把SetUp中添加的Author对象保存为测试类的字段,测试方法里直接关联这个实例:
    private Author _testAuthor;
    private YourDbContext _dbContext;
    
    [SetUp]
    public void Setup()
    {
        var options = new DbContextOptionsBuilder<YourDbContext>()
            .UseInMemoryDatabase(databaseName: "TestDB")
            .Options;
        _dbContext = new YourDbContext(options);
        _testAuthor = new Author { Name = "Test Author" };
        _dbContext.Author.Add(_testAuthor);
        _dbContext.SaveChanges();
    }
    
    [Test]
    public void AddBookWithExistingAuthorTest()
    {
        var book = new Book { Author = _testAuthor };
        _dbContext.Book.Add(book);
        _dbContext.SaveChanges();
        // 断言逻辑
    }
    
  • 使用AsNoTracking()获取已存在的Author:如果你需要从上下文重新查询,加上AsNoTracking()让上下文不跟踪这个实例:
    var existingAuthor = _dbContext.Author.AsNoTracking().FirstOrDefault(a => a.AuthorId == testAuthorId);
    var book = new Book { Author = existingAuthor };
    
  • 每个测试实例化新的DbContext:确保每个测试都用独立的上下文实例,避免跨测试的跟踪冲突(InMemory数据库可以指定不同的数据库名,或者在[TearDown]中销毁上下文)。

内容的提问来源于stack exchange,提问作者Riya Roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:52:53