在.net core中使用dapper进行递归查询

recursive query using dapper in .net core

我有一个 table(广告系列)有 self-referencing,设计如下所示;

   public class Campaign: SqlEntityBase
    {
        public int ParentCampaignId { get; set; }
        public string Name { get; set; }
        public Campaign ParentCampaign { get; set; }
    }
// ParentCampaignId is FK to itself

现在我需要检索包含其 child、

的广告系列

我正在尝试检索 ID=6 的实体,

下面的代码适用于第一个 child(4),但无法检索其中的 child(2)。

可能有更多嵌套实体我如何检索所有 child 个实体...

Class:

 public async Task<Campaign> GetAsync(int id)
        {
            using var dbConnection = _context.CreateConnection();
            string query = @"SELECT d.[Id], d.[ParentCampaignId], d.[Name] FROM [dbo].[Campaign] d 
                             join [dbo].[Campaign] dc on 
                             d.ParentCampaignId = dc.Id 
                             WHERE d.[Id] = @Id";
                var users = await dbConnection.QueryAsync<Campaign, Campaign, Campaign>(query, (p, camp) =>
                {
                    p.ParentCampaign = camp;
                    return p;
                }, splitOn: "Id,ParentCampaignId", param: new { Id = id });
                return users.FirstOrDefault();
            }

仅仅做多重映射在这里是行不通的,因为你想得到递归的结果。

您可以使用递归 CTE 查询来获取所有父行。然后,您有两个选项可以将它们映射到:

  • 您可以使用 Dictionary 映射它们,首先加载它们,然后再次遍历它们并分配父对象。
  • 或者您可以确保递归 returns 的顺序正确(通过使用 ORDER BY)并只跟踪最后一个。
public class Campaign : SqlEntityBase
{
    public int Id { get; set; }
    public int ParentCampaignId { get; set; }
    public string Name { get; set; }
    public Campaign ParentCampaign { get; set; }
}

public async Task<Campaign> GetAsync(int id)
{
    using var dbConnection = _context.CreateConnection();
    string query = @"
WITH cte AS (
    SELECT d.Id, d.ParentCampaignId, d.Name, 0 AS lvl
      FROM dbo.Campaign c
      WHERE c.Id = @Id

    UNION ALL

    SELECT c.Id, c.ParentCampaignId, c.Name, cte.lvl + 1
      FROM dbo.Campaign c
      JOIN cte on cte.ParentCampaignId = c.Id 
)
SELECT d.Id, d.ParentCampaignId, d.Name
FROM dbo.Campaign d 
ORDER BY lvl;
";
    Campaign first = null;
    Campaign previous = null;
    foreach (var user in await dbConnection.QueryAsync<Campaign>(query))
    {
        if (first == null)
        {
            first = campaign;
            previous = campaign;
        }
        else
        {
            previous.Parent = campaign;
            previous = campaign;
        }
    }
    return first;
}