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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:01:16