1

dto のツリー階層を構築するのに苦労しています。ツリー階層は、深さのあるクロージャ テーブルに取り込まれます。クロージャー テーブルは、データベース内のトリガーを使用して構築され、EF の Teams テーブルにリレーショナルにマップされません。

これは私の基本的なクラス構造です:

public class Team
{
  public Guid Id {get; set;}
  public string Title {get; set;}
  public Guid? ParentTeamId {get; set;}
  public Team ParentTeam {get; set;}
}

public class TeamDto
{
  public Guid Id {get; set;}
  public string Title {get; set;}
  public Guid? ParentTeamId {get; set;}
  public ICollection<TeamDto> SubTeams {get; set;} = new List<TeamDto>();
}

Closure テーブルは次のように構成されています。

public class Closure
{
  public Guid ParentId {get; set;}
  public Guid ChildId {get; set;}
  public int Depth {get; set;}
}

EF の定義は次のとおりです。

public void Configure(EntityTypeBuilder<Team> builder)
    {
        builder.HasOne(p => p.ParentTeam)
            .WithMany()
            .HasForeignKey(k => k.ParentTeamId)
            .IsRequired(false)
            .OnDelete(DeleteBehavior.Cascade);
    }
public void Configure(EntityTypeBuilder<Closure> builder)
    {
        builder.HasKey(aa => new {aa.ChildId, aa.ParentId});
    }

これに対してクエリを実行するときに私ができる最善のことは、最初のレベルでサブチームを埋めることです。私は AutoMapper を使用していますが、AutoMapper ソリューションには慣れていません。

ユーザーに関連するチームのリストを取得するための私のクエリ (既に teamMemberships リストにキャプチャされており、_mapper は AutoMapper インジェクションで、_context はデータベース コンテキスト インジェクションです) は次のようになります。

var teamList = await _context.Closures
                .Where(x => teamMemberships.Contains(x.ChildId))
                .Select(x => x.ParentId)
                .ToListAsync();

var query = _context.Teams
  .Where(d => teamList.Contains(d.Id) && x.ParentTeamId == null)
  .Select(x => new TeamDto
  {
    Id = x.Id,
    ParentTeamId = x.ParentTeamId,
    Title = x.Title,
    SubTeams = _mapper.Map<List<TeamDto>>(_context.Teams.Where(y => y.ParentTeamId == x.Id))
   })
   .AsQueryable();

完全なツリーが Dto で確立されるように、どうにかしてサブチームを再帰的に引き出す必要があります。これを行うことができる閉鎖テーブルを参照するクエリがあるかもしれないと考えています。json として送信された場合の dto は、次のようになります。

[
  {
    "id": "e5500e84-21fb-4b5e-aa9b-a95e51d3dd05",
    "parentId": null,
    "title": "Team 1",
    "subTeams": [
      {
        "id": "05a8d423-feb1-4ea6-9596-d26b18feaa9e",
        "parentId": "e5500e84-21fb-4b5e-aa9b-a95e51d3dd05",
        "title": "Team 1.1",
        "subTeams": [
          {
            "id": "251358d9-3c5a-43b5-91f1-c2e82778c50b",
            "parentId": "05a8d423-feb1-4ea6-9596-d26b18feaa9e",
            "title": "Team 1.1.1",
            "subTeams": []
          },
          {
            "id": "4e27be0b-3a7b-4c8c-8039-2a18e1afcbd0",
            "parentId": "05a8d423-feb1-4ea6-9596-d26b18feaa9e",
            "title": "Team 1.1.2",
            "subTeams": []
          }
        ]
      },
      {
        "id": "2a4d56fc-00f0-4418-80a2-7d870c0ddee5",
        "parentId": "e5500e84-21fb-4b5e-aa9b-a95e51d3dd05",
        "title": "Team 1.2",
        "subTeams": []
      }
    ]
  },
  ...
]

どんな洞察も大歓迎です。

4

1 に答える 1

1

答えてくれたGert Arnoldと他の人たちに感謝します。

私の解決策には、再帰関数が含まれていました。チーム クロージャ テーブルを使用して関連するすべてのチームをプルし、そのプルからメモリ内にツリーを構築しました。

// teamMemberships is a list of teamIds that are relevant to the user
// I pull all related teams to that list (because a user, for example is a member
// of Team 1 implicitly if they are a member of 1.1, but not explicitly) because
// I need all ancestors and descendants of the selected teams
            var allRelatedTeams = await _context.TeamClosures
                .Where(x => teamMemberships.Contains(x.ChildId) || teamMemberships.Contains(x.ParentId))
                .Select(x => x.ParentId)
                .ToListAsync();

            var teams = _context.Teams
                .Where(x => allRelatedTeams.Contains(x.Id))
                .ProjectTo<TeamDto>(_mapper.ConfigurationProvider)
                .AsQueryable();
            
            var query = teams
                .Where(x => x.ParentTeamId == null)
                .AsQueryable();

            foreach (var team in query)
            {
                ParseSubTeams(team, await teams.ToListAsync());
            }

再帰関数:

        private void ParseSubTeams(TeamDto team, List<TeamDto> teamList)
        {
            var childTeams = teamList
                .Where(x => _context.TeamClosures
                    .Where(y => y.ParentId == team.Id)
                    .Select(z => z.ChildId)
                    .ToList().Contains(x.Id))
                .ToList();
            foreach (var subTeam in childTeams)
            {
                if (subTeam.ParentTeamId == team.Id)
                {
                    team.SubTeams.Add(_mapper.Map<TeamDto>(subTeam));
                    ParseSubTeams(subTeam, teamList);
                }
            }
        }

            
于 2021-10-09T16:07:21.060 に答える