EF Core:何时设置ID/对象?如何仅新增关联现有Book的Author
实体类定义
public class Book { public int Id { get; set; } public string Name { get; set; } = string.Empty; public int? AddedByUserId { get; set; } public virtual ICollection<Author> Authors { get; set; } = new HashSet<Author>(); } public class Author { public int Id { get; set; } public int BookId { get; set; } public string Name { get; set; } = string.Empty; public int? AddedByUserId { get; set; } public Book Book { get; set; } = new Book(); }
尝试的操作代码
我尝试新增Author并关联现有Book(ID为1),代码如下:
var newAuthor = new Author(); newAuthor.BookId = 1; _dbContext.Authors.Add(newAuthor);
异常现象
通过ChangeTracker.DebugView.LongView查看操作计划时,发现EF Core准备新增Author、Book和User三个实体:
Author {Id: -2147482646} **Added** Id: -2147482646 PK Temporary AddedByUserId: 1 DateAdded: '11/25/2022 8:22:11 PM' Name: 'My Author Name' BookId: -2147482643 FK Temporary Book: {Id: -2147482643} Book {Id: -2147482643} **Added** Id: -2147482643 PK Temporary AddedByUserId: -2147482645 FK Temporary DateAdded: '1/1/0001 12:00:00 AM' Name: '' AddedByUserId: {Id: -2147482645} User {Id: -2147482645} **Added** Id: -2147482645 PK Temporary DateAdded: '1/1/0001 12:00:00 AM' Name: <null> RowVersion: <null>
问题根源
问题出在Author类的Book属性默认初始化了new Book()。当调用_dbContext.Authors.Add(newAuthor)时,EF Core的ChangeTracker会自动发现关联的未被上下文跟踪的Book实例,将其标记为Added状态,进而尝试插入新的Book,连带触发关联的User新增。
正确解决方式
方式1:修正实体类初始化逻辑(推荐)
将Author类中Book属性的默认初始化改为null,设置BookId时就不会触发新Book的追踪:
public class Author { // ...其他属性 public Book? Book { get; set; } = null; // 改为null初始化 }
之后直接设置BookId即可:
var newAuthor = new Author(); newAuthor.BookId = 1; newAuthor.Name = "My Author Name"; newAuthor.AddedByUserId = 1; _dbContext.Authors.Add(newAuthor); _dbContext.SaveChanges();
方式2:手动Attach现有Book(避免数据库查询)
如果不想修改实体类,可以创建仅包含Id的Book实例,通过Attach将其标记为上下文已跟踪的现有实体,再关联到Author:
var existingBook = new Book { Id = 1 }; _dbContext.Attach(existingBook); // 标记为已跟踪的未修改实体 var newAuthor = new Author(); newAuthor.Book = existingBook; // 关联已跟踪的Book newAuthor.Name = "My Author Name"; newAuthor.AddedByUserId = 1; _dbContext.Authors.Add(newAuthor); _dbContext.SaveChanges();
方式3:查询现有Book并关联(简单直观)
就是你提到的方式,直接从数据库查询现有Book并赋值给Author的Book属性。这种方式会触发一次数据库查询,但逻辑最直观:
var existingBook = _dbContext.Books.Find(1); if (existingBook != null) { var newAuthor = new Author(); newAuthor.Book = existingBook; newAuthor.Name = "My Author Name"; newAuthor.AddedByUserId = 1; _dbContext.Authors.Add(newAuthor); _dbContext.SaveChanges(); }
内容的提问来源于stack exchange,提问作者user20326571
相关产品推荐
相关产品推荐

