在.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;
}
我有一个 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;
}