EF Core:多对多多级关联的Include查询配置问题
实现方案:通过EF Core实体配置实现用户关联去重用例列表
1. 明确实体与数据库关系
你的数据关系是:用户(AppConfigUser)与角色(Role)为多对多,角色与用例(UseCase)为多对多。要在AppConfigUser中直接获取去重的用例列表,需要先补全实体的导航属性,再通过EF Core配置实现关联。
补全后的核心实体类示例:
public class AppConfigUser { public int Id { get; set; } public string? FirstName { get; set; } // 用户关联的角色集合 public List<Role> Roles { get; set; } = new(); // 目标:去重的用户可访问用例集合 public List<UseCase> UseCases { get; set; } = new(); } public class Role { public int Id { get; set; } public string Name { get; set; } = string.Empty; public List<AppConfigUser> Users { get; set; } = new(); public List<UseCase> UseCases { get; set; } = new(); } public class UseCase { public int Id { get; set; } public string Code { get; set; } = string.Empty; public List<Role> Roles { get; set; } = new(); }
2. 通过实体配置实现直接关联去重用例
在DbContext的OnModelCreating方法中,配置多对多关联,并通过虚拟中间表实现用户到用例的直接关联(自动去重):
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置用户-角色多对多(对应你的AppConfigUserUserRole中间表) modelBuilder.Entity<AppConfigUser>() .HasMany(u => u.Roles) .WithMany(r => r.Users) .UsingEntity(j => j.ToTable("AppConfigUserUserRole")); // 配置角色-用例多对多(对应你的RoleUseCase中间表) modelBuilder.Entity<Role>() .HasMany(r => r.UseCases) .WithMany(u => u.Roles) .UsingEntity(j => j.ToTable("RoleUseCase")); // 关键:配置用户到用例的直接关联,通过SQL查询自动去重 modelBuilder.Entity<AppConfigUser>() .HasMany(u => u.UseCases) .WithMany() .UsingEntity<Dictionary<string, object>>( "AppConfigUserUseCase", j => j.HasOne<UseCase>().WithMany().HasForeignKey("UseCaseId"), j => j.HasOne<AppConfigUser>().WithMany().HasForeignKey("AppConfigUserId"), j => { j.HasKey("AppConfigUserId", "UseCaseId"); // 自定义SQL实现用户-角色-用例的关联查询并去重 j.ToSqlQuery(@" SELECT DISTINCT u.Id AS AppConfigUserId, uc.Id AS UseCaseId FROM AppConfigUser u JOIN AppConfigUserUserRole ur ON u.Id = ur.AppConfigUserId JOIN Role r ON ur.RoleId = r.Id JOIN RoleUseCase ruc ON r.Id = ruc.RoleId JOIN UseCase uc ON ruc.UseCaseId = uc.Id "); }); }
3. 直接查询并Include用例列表
配置完成后,即可通过Include直接获取用户的去重用例:
var users = _dbContext.Users.Include(u => u.UseCases).ToList();
如果觉得实体配置过于复杂,也可以直接通过投影查询实现去重(无需额外配置):
var users = _dbContext.Users .Select(u => new AppConfigUser { Id = u.Id, FirstName = u.FirstName, UseCases = u.Roles.SelectMany(r => r.UseCases).Distinct().ToList() }) .ToList();
注意事项
- 若使用EF Core 3.x及以下版本,多对多需显式创建中间实体,此时更推荐用投影查询实现去重。
- 确保数据库中间表无重复关联数据,避免不必要的去重开销。
内容的提问来源于stack exchange,提问作者AxSc
相关产品推荐
相关产品推荐

