如何解决EF Core + Automapper ProjectTo 中的递归 CTE 使用 EF Core 调用函数 Content将 [ { "commentId": "be02742a-9170-4335-afe7-3c7c22684424", "content": "Hello World!", "postId": "69f3ca3a-66fc-4142-873d-01e9
在我的项目中,我有 structlog
和 Comment
类型:
CommentDto
public class Comment
{
public Guid CommentId { get; set; }
public string Content { get; set; }
public Guid PostId { get; set; }
public virtual Post Post { get; set; }
public Guid? ParentCommentId { get; set; }
public virtual Comment ParentComment { get; set; }
public virtual ICollection<Comment> InverseParentComment { get; set; }
}
class CommentDto
{
public Guid CommentId { get; set; }
public string Content { get; set; }
public Guid? ParentCommentId { get; set; }
public ICollection<CommentDto> InverseParentComment { get; set; }
}
将映射到 Comment
。这是configuration:
CommentDto
cfg.CreateMap<Comment,CommentDto>();
这个函数允许获取给定帖子的评论层次(它需要一个帖子的 ID)。
为了使其更具可读性,我按层次顺序表示它(仅 FUNCTION [dbo].[fn_PostCommentHierarchy] (@postId UNIQUEIDENTIFIER)
RETURNS TABLE
AS
RETURN
(
WITH cte AS
(
SELECT CommentId,Content,PostId,ParentCommentId
FROM dbo.Comment
WHERE ParentCommentId IS NULL and PostId = @postId
UNION ALL
SELECT child.CommentId,child.Content,child.PostId,child.ParentCommentId
FROM dbo.Comment child
INNER JOIN cte parent
ON parent.CommentId = child.ParentCommentId
WHERE parent.PostId = @postId
)
SELECT * FROM cte
);
属性):
- 世界你好!
- 您是程序员吗?
- 当然
- 什么?
- 您是程序员吗?
- 我也想去火星!
- 月球上见:)
使用 EF Core 调用函数 Content
fn_PostCommentHierarchy
EF Core 向 sql-Server 发送以下 sql 查询:List<Comment> commentHierarchy = await _context.Comment
.FromsqlInterpolated($"SELECT CommentId,ParentCommentId FROM dbo.fn_PostCommentHierarchy('post-id-here')")
.ToListAsync();
上面的代码按预期工作(使用 JSON 格式来提高可读性):
SELECT CommentId,ParentCommentId FROM dbo.fn_PostCommentHierarchy('post-id-here')
将 [
{
"commentId": "be02742a-9170-4335-afe7-3c7c22684424","content": "Hello World!","postId": "69f3ca3a-66fc-4142-873d-01e950d83adf","post": null,"parentCommentId": null,"parentComment": null,"commentRates": [],"inverseParentComment": [
{
"commentId": "59656765-d1ed-4648-8696-7d576ab7419f","content": "Are you a programmer?","parentCommentId": "be02742a-9170-4335-afe7-3c7c22684424","inverseParentComment": [
{
"commentId": "0bb77a43-c7bb-482f-9bf8-55c4050974da","content": "Sure","parentCommentId": "59656765-d1ed-4648-8696-7d576ab7419f","inverseParentComment": []
},{
"commentId": "b8d61cfd-d274-4dae-a2be-72e08cfa9066","content": "What?","inverseParentComment": []
}
]
}
]
},{
"commentId": "cfe126b3-4601-4432-8c87-445c1362a225","content": "I wanna go to Mars too!","inverseParentComment": [
{
"commentId": "ab6d6b49-d772-48cd-9477-8d40f133c37a","content": "See you on the Moon :)","parentCommentId": "cfe126b3-4601-4432-8c87-445c1362a225","inverseParentComment": []
}
]
},{
"commentId": "ab6d6b49-d772-48cd-9477-8d40f133c37a","parentComment": {
"commentId": "cfe126b3-4601-4432-8c87-445c1362a225","inverseParentComment": []
},"inverseParentComment": []
},{
"commentId": "59656765-d1ed-4648-8696-7d576ab7419f","parentComment": {
"commentId": "be02742a-9170-4335-afe7-3c7c22684424","inverseParentComment": [
{
"commentId": "0bb77a43-c7bb-482f-9bf8-55c4050974da",{
"commentId": "b8d61cfd-d274-4dae-a2be-72e08cfa9066","inverseParentComment": []
}
]
},{
"commentId": "0bb77a43-c7bb-482f-9bf8-55c4050974da","parentComment": {
"commentId": "59656765-d1ed-4648-8696-7d576ab7419f","parentComment": {
"commentId": "be02742a-9170-4335-afe7-3c7c22684424","inverseParentComment": [
{
"commentId": "b8d61cfd-d274-4dae-a2be-72e08cfa9066","inverseParentComment": []
}
]
},{
"commentId": "b8d61cfd-d274-4dae-a2be-72e08cfa9066","inverseParentComment": []
}]
映射到 Comment
上面的代码适用于实体类型 CommentDto
,但我想将其映射到 Comment
。因此,让我们为此目的使用 CommentDto
:
ProjectTo
注意:List<CommentDto> commentHierarchy = await _context.Comment
.FromsqlInterpolated($"SELECT CommentId,ParentCommentId FROM dbo.fn_PostCommentHierarchy('post-id-here')")
.ProjectTo<CommentDto>(_mapper.ConfigurationProvider)
.ToListAsync();
是 _mapper
类型的对象。
我认为,结果应该类似于我在使用 IMapper
之前得到的结果。但它看起来像:
ProjectTo
注意:我做了粗体评论,没有父级评论(根评论)。
比较使用 [
{
"commentId": "be02742a-9170-4335-afe7-3c7c22684424","inverseParentComment": null
}
]
},"inverseParentComment": null
}
]
},"inverseParentComment": null
},"inverseParentComment": []
}
]
之前和之后的结果。为什么它们不同?
对于上面的代码,EF Core 向 sql-server 发送以下 sql 查询:
ProjectTo
问题
为什么使用SELECT [c].[CommentId],[c].[Content],[c].[ParentCommentId],[c0].[CommentId],[c0].[Content],[c0].[ParentCommentId]
FROM (
SELECT CommentId,ParentCommentId FROM dbo.fn_PostCommentHierarchy('69f3ca3a-66fc-4142-873d-01e950d83adf')
) AS [c]
LEFT JOIN [Comment] AS [c0] ON [c].[CommentId] = [c0].[ParentCommentId]
ORDER BY [c].[CommentId],[c0].[CommentId]
之前的结果和使用ProjectTo
之后的结果不一样?
如何解决这个问题?
更新 1
根据 Svyatoslav Danyliv 的说法:
递归CTE返回平面列表,那么你必须建立层次结构 再次。
但为什么在这种情况下我应该使用递归 CTE?
以下解决方案的工作方式相同:
ProjectTo
注意:我使用了 List<CommentDto> commentFlatList = await _context.Comment
.Where(c => c.PostId == Guid.Parse("post-id-here"))
.ProjectTo<CommentDto>(_mapper.ConfigurationProvider)
.ToListAsync();
Dictionary<Guid,CommentDto> commentDictionary = commentFlatList
.ToDictionary(c => c.CommentId);
foreach (var comment in commentFlatList)
{
if (comment.ParentCommentId == null)
{
continue;
}
if (commentDictionary.TryGetValue((Guid) comment.ParentCommentId,out CommentDto parent))
{
parent.Children.Add(comment);
}
}
List<CommentDto> commentHierarchy = commentFlatList.Where(c => c.ParentCommentId == null);
而不是 Dictionary
(see this example),但这并没有改变这个想法。
更新 2
让我们看看更新 1 中的代码:
Lookup
它将被 EF Core 翻译成以下内容:
List<CommentDto> commentFlatList = await _context.Comment
.Where(c => c.PostId == Guid.Parse("post-id-here"))
.ProjectTo<CommentDto>(_mapper.ConfigurationProvider)
.ToListAsync();
解决方法
递归 CTE 返回平面列表,然后您必须再次构建层次结构。
var commentHierarchy = await _context.Comment
.FromSqlInterpolated($"SELECT CommentId,Content,PostId,ParentCommentId FROM dbo.fn_PostCommentHierarchy('post-id-here')")
.ProjectTo<CommentDto>(_mapper.ConfigurationProvider)
.ToListAsync();
var lookup = commentHierarchy.ToLookup(x => x.commentId);
foreach (var c in commentHierarchy)
{
if (lookup.Contains(c.commentId))
c.inverseParentComment.AddRange(lookup.Item[c.commentId]);
}
var result = commentHierarchy.Where(c => c.parentCommentId == null);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。