.NET 5 EF Core 三方多对多映射配置报错如何解决?
三方多对多关联正确实现方案
错误原因排查
- 第一个报错
The property or navigation 'Instruction' cannot be added...是因为你重复定义了同名导航:要么已经在PersonSkillInstruction类中通过数据注解配置过Instruction导航关联,又在Fluent API中重复调用HasOne(x=>x.Instruction)生成重复配置;要么是外键字段名和导航属性名重名导致冲突。 - 第二个报错
The property 'PersonSkillInstruction.Instruction' is of type 'InstructionEntity' which is not supported...是因为你只配置了联合主键,没有显式配置导航属性的关联关系,EF Core无法识别Instruction是导航属性,将其当成普通字段尝试映射到数据库,而SQL Server不支持直接存储自定义实体类,因此抛出类型不支持错误。
1. 实体类定义
// 人员实体 public class PersonEntity { public int Id { get; set; } public string Name { get; set; } // 关联导航 public ICollection<PersonSkillInstruction> PersonSkillInstructions { get; set; } = new List<PersonSkillInstruction>(); } // 技能实体 public class SkillEntity { public int Id { get; set; } public string SkillName { get; set; } // 关联导航 public ICollection<PersonSkillInstruction> PersonSkillInstructions { get; set; } = new List<PersonSkillInstruction>(); } // 操作指引实体 public class InstructionEntity { public int Id { get; set; } public string Content { get; set; } // 关联导航 public ICollection<PersonSkillInstruction> PersonSkillInstructions { get; set; } = new List<PersonSkillInstruction>(); } // 三方关联中间实体 public class PersonSkillInstruction { // 三个外键字段 public int PersonId { get; set; } public int SkillId { get; set; } public int InstructionId { get; set; } // 三个对应主实体的导航属性 public PersonEntity Person { get; set; } public SkillEntity Skill { get; set; } public InstructionEntity Instruction { get; set; } }
2. DbContext配置
首先在DbContext中添加对应的DbSet:
public DbSet<PersonEntity> Persons { get; set; } public DbSet<SkillEntity> Skills { get; set; } public DbSet<InstructionEntity> Instructions { get; set; } public DbSet<PersonSkillInstruction> PersonSkillInstructions { get; set; }
然后在OnModelCreating方法中配置关联关系:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置中间表联合主键:如果业务允许同一人+同一技能绑定多个相同指引,可以新增单独自增主键Id,无需联合主键 modelBuilder.Entity<PersonSkillInstruction>() .HasKey(psi => new { psi.PersonId, psi.SkillId, psi.InstructionId }); // 配置和人员实体的关联 modelBuilder.Entity<PersonSkillInstruction>() .HasOne(psi => psi.Person) .WithMany(p => p.PersonSkillInstructions) .HasForeignKey(psi => psi.PersonId) .OnDelete(DeleteBehavior.Restrict); // 按需配置删除行为,避免级联删除循环 // 配置和技能实体的关联 modelBuilder.Entity<PersonSkillInstruction>() .HasOne(psi => psi.Skill) .WithMany(s => s.PersonSkillInstructions) .HasForeignKey(psi => psi.SkillId) .OnDelete(DeleteBehavior.Restrict); // 配置和操作指引实体的关联 modelBuilder.Entity<PersonSkillInstruction>() .HasOne(psi => psi.Instruction) .WithMany(i => i.PersonSkillInstructions) .HasForeignKey(psi => psi.InstructionId) .OnDelete(DeleteBehavior.Restrict); }
3. 注意事项
- 不要在
PersonSkillInstruction的导航属性上重复加[ForeignKey]等数据注解,避免和Fluent API配置冲突 - 执行迁移前可以先调用
modelBuilder.Validate()验证配置是否存在冲突 - 如果需要查询指定人员+技能对应的所有指引,可以直接通过关联表导航查询:
var instructions = _context.PersonSkillInstructions .Where(psi => psi.PersonId == 1 && psi.SkillId == 2) .Include(psi => psi.Instruction) .Select(psi => psi.Instruction) .ToList();
内容的提问来源于stack exchange,提问作者Radu
相关产品推荐
相关产品推荐

