EF Core如何配置来自两张独立表的复合主键并实现关联查询
结论
你期望的Include直接传UserId的写法EF Core原生不支持,原表EmployeeRelationship用ClientId+UserId做复合主键是带自定义属性的多对多关联的标准设计,没有问题,主键命名规则不一致也不会造成影响,以下是两种可行的实现方案:
方案1:投影查询(无侵入,无需修改实体配置)
直接在查询时手动关联EmployeeRelationship表,传入当前UserId匹配即可,示例代码如下:
// currentUserId为当前登录用户的ID变量 var clientList = await Context.Clients .Select(c => new Client { // 赋值Client所有原有字段 ClientId = c.ClientId, Name = c.Name, // 其余字段逐一赋值 EmployeeRelationship = Context.EmployeeRelationships .FirstOrDefault(er => er.ClientId == c.ClientId && er.UserId == currentUserId) }) .ToListAsync();
注意需要给Client实体的EmployeeRelationship属性加上[NotMapped]注解,避免EF Core将其识别为表字段:
public class Client { public int ClientId { get; set; } // 其余原有字段 [NotMapped] public EmployeeRelationship? EmployeeRelationship { get; set; } }
方案2:配置一对多关联+过滤Include(符合EF Core规范)
先配置实体间的关联关系,Client和User都和EmployeeRelationship是一对多关联,配置代码如下:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置复合主键 modelBuilder.Entity<EmployeeRelationship>() .HasKey(er => new { er.ClientId, er.UserId }); // 配置Client和EmployeeRelationship的一对多关联 modelBuilder.Entity<EmployeeRelationship>() .HasOne<Client>() .WithMany(c => c.EmployeeRelationships) .HasForeignKey(er => er.ClientId); // 配置User和EmployeeRelationship的一对多关联 modelBuilder.Entity<EmployeeRelationship>() .HasOne<User>() .WithMany(u => u.EmployeeRelationships) .HasForeignKey(er => er.UserId); }
对应的实体属性补充:
public class Client { public int ClientId { get; set; } // 其余原有字段 public ICollection<EmployeeRelationship> EmployeeRelationships { get; set; } = new List<EmployeeRelationship>(); // 快捷访问属性,加NotMapped避免EF Core映射 [NotMapped] public EmployeeRelationship? EmployeeRelationship => EmployeeRelationships.FirstOrDefault(); } public class User { public int UserId { get; set; } // 其余原有字段 public ICollection<EmployeeRelationship> EmployeeRelationships { get; set; } = new List<EmployeeRelationship>(); }
查询时使用EF Core 5及以上版本支持的过滤Include即可:
var clientList = await Context.Clients .Include(c => c.EmployeeRelationships.Where(er => er.UserId == currentUserId)) .ToListAsync();
查询完成后直接通过client.EmployeeRelationship?.Description即可访问对应关系描述。
内容的提问来源于stack exchange,提问作者Mr.Technician
相关产品推荐
相关产品推荐

