EF Core中Book关联Author时的实体跟踪问题求助(NUnit测试)
让我逐个拆解你遇到的问题,帮你理清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

