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

EF Core:何时设置ID/对象?如何仅新增关联现有Book的Author

EF Core新增Author时仅关联现有Book的解决方案

实体类定义

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:22:03