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

Code First:如何让EF Core自动生成多对多关系映射表?

EF Core 多对多关系自动生成关联表的实现方法

你当前遇到的问题是:仅在Visit类中定义List<Procedure>时,EF Core会默认识别为一对多关系(一个Visit对应多个Procedure),因此会在Procedure表中添加外键列。但你需要的是多对多关系(一个Visit可关联多个Procedure,一个Procedure也可被多个Visit关联),以下是两种实现方案:

方案一:EF Core 5.0+ 自动生成关联表(无需手动创建关联类)

从EF Core 5.0开始,支持无显式连接实体的多对多关系,只需通过配置或双向导航属性让EF自动识别:

1. 添双向导航属性(推荐,帮助EF自动识别关系)

在Procedure类中添加反向导航属性:

public class Procedure
{
    [Key]
    public int ProcedureId { get; set; }
    public string ProcedureName { get; set; }
    // 新增反向导航
    public List<Visit> Visits { get; set; }
}

2. 配置多对多关系(二选一)

方式A:Fluent API配置(自定义程度更高)

在你的DbContext中重写OnModelCreating方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Visit>()
        .HasMany(v => v.Procedures)
        .WithMany(p => p.Visits)
        // 可选:自定义关联表名称和列名、外键约束等
        .UsingEntity(j => j.ToTable("VisitProcedures")
            .HasOne<Procedure>()
            .WithMany()
            .HasForeignKey("ProcedureId")
            .OnDelete(DeleteBehavior.Restrict)
            .HasOne<Visit>()
            .WithMany()
            .HasForeignKey("VisitId")
            .OnDelete(DeleteBehavior.Cascade)));
}

方式B:仅靠双向导航属性自动生成

如果已添加双向导航属性(Visit.Procedures和Procedure.Visits),EF Core 5.0+会自动识别多对多关系,生成默认名为VisitProcedures的关联表(命名规则:按实体名字母顺序拼接),表中包含VisitId和ProcedureId两个外键列。

方案二:手动创建关联类(兼容所有EF Core版本,或需存储额外关联信息)

如果你的EF Core版本低于5.0,或者需要在关联表中添加额外字段(如关联时间、操作人等),则必须手动创建连接实体:

1. 创建关联类

public class VisitProcedure
{
    public int VisitId { get; set; }
    public Visit Visit { get; set; }
    public int ProcedureId { get; set; }
    public Procedure Procedure { get; set; }
    // 可添加额外字段,例如:
    // public DateTime CreatedAt { get; set; }
}

2. 配置关系

在DbContext的OnModelCreating中配置复合主键与关联关系:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 配置复合主键
    modelBuilder.Entity<VisitProcedure>()
        .HasKey(vp => new { vp.VisitId, vp.ProcedureId });

    // 关联Visit
    modelBuilder.Entity<VisitProcedure>()
        .HasOne(vp => vp.Visit)
        .WithMany(v => v.VisitProcedures)
        .HasForeignKey(vp => vp.VisitId);

    // 关联Procedure
    modelBuilder.Entity<VisitProcedure>()
        .HasOne(vp => vp.Procedure)
        .WithMany(p => p.VisitProcedures)
        .HasForeignKey(vp => vp.ProcedureId);
}

同时修改Visit和Procedure的导航属性:

public class Visit
{
    [Key]
    public int VisitId { get; set; }
    public DateTime VisitDate { get; set; }
    public string Description { get; set; }
    // 改为关联连接实体
    public List<VisitProcedure> VisitProcedures { get; set; }
}

public class Procedure
{
    [Key]
    public int ProcedureId { get; set; }
    public string ProcedureName { get; set; }
    // 改为关联连接实体
    public List<VisitProcedure> VisitProcedures { get; set; }
}

加载关联数据

方案一(自动生成关联表时)

直接用Include加载关联的Procedure:

var visitsWithProcedures = dbContext.Visits
    .Include(v => v.Procedures)
    .ToList();

方案二(手动关联类时)

使用ThenInclude嵌套加载:

var visitsWithProcedures = dbContext.Visits
    .Include(v => v.VisitProcedures)
    .ThenInclude(vp => vp.Procedure)
    .ToList();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:42:57