EF6查询多对多关系时生成含不存在表名的SQL语句
问题原因与解决方法
核心问题分析
你的代码存在几处关键错误,导致EF生成了不存在的ReportDataSections1表:
- 重复定义多对多关系:既手动创建了中间表实体
ReportDataSection,又在Report和DataSection中定义了直接的多对多导航属性(DataSections/Reports),EF会将这视为两个独立的多对多关系,自动生成额外的连接表。 - 实体类语法错误:
- 集合属性初始化错误:不能用
DbSet<T>初始化实体类中的导航集合,应该用HashSet<T>这类普通集合。 - 导航属性拼写错误(
ReportDataSectios少了一个n)。 ReportDataSection中的导航属性缺少属性名(public virtual DataSection { get; set; }语法不合法)。
- 集合属性初始化错误:不能用
- ModelBuilder配置错误:配置关系时引用的导航属性名称不正确,且未明确外键关联。
修正步骤
1. 修正实体类代码
public class Report { [Key] public int ReportId { get; set;} // 修正拼写错误,改用HashSet初始化 public virtual ICollection<ReportDataSection> ReportDataSections { get; } = new HashSet<ReportDataSection>(); // 移除直接的DataSections导航属性,避免重复关系 // Other properties } public class DataSection { [Key] public int DataSectionId { get; set; } // 改用HashSet初始化 public virtual ICollection<ReportDataSection> ReportDataSections { get; } = new HashSet<ReportDataSection>(); // 移除直接的Reports导航属性,避免重复关系 // Other properties } public class ReportDataSection { [Key] [Column(Order = 0)] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int ReportId { get; set; } [Key] [Column(Order = 1)] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int DataSectionId { get; set; } public int OrderSeq { get; set; } // 修正导航属性,添加属性名 public virtual DataSection DataSection { get; set; } public virtual Report Report { get; set; } } public class DbModel : DbContext { public virtual DbSet<DataSection> DataSections { get; set; } public virtual DbSet<Report> Reports { get; set; } // 添加中间表的DbSet,确保EF能正确映射 public virtual DbSet<ReportDataSection> ReportDataSections { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // skipping irrelevant calls // 明确配置DataSection与ReportDataSection的一对多关系 modelBuilder.Entity<DataSection>() .HasMany(ds => ds.ReportDataSections) .WithRequired(rds => rds.DataSection) .HasForeignKey(rds => rds.DataSectionId) .WillCascadeOnDelete(false); // 明确配置Report与ReportDataSection的一对多关系 modelBuilder.Entity<Report>() .HasMany(r => r.ReportDataSections) .WithRequired(rds => rds.Report) .HasForeignKey(rds => rds.ReportId) .WillCascadeOnDelete(false); // 显式配置复合主键(可选,因为已经用特性标注,不过显式配置更清晰) modelBuilder.Entity<ReportDataSection>() .HasKey(rds => new { rds.ReportId, rds.DataSectionId }); } }
2. 修正查询代码
现在通过ReportDataSections导航属性关联Report,并保留OrderSeq字段:
IQueryable<DataSection> query = _db.DataSections.Where(ds => ds.DataSectionId == id); // 先Include中间表,再通过ThenInclude关联Report query = query.Include(ds => ds.ReportDataSections) .ThenInclude(rds => rds.Report);
说明
通过移除Report和DataSection之间的直接多对多导航属性,EF只会识别你手动定义的ReportDataSection中间表,不会生成多余的连接表。同时保留了OrderSeq字段,满足排序需求。
内容的提问来源于stack exchange,提问作者Tony Vitabile
相关产品推荐
相关产品推荐

