微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

EF Core + Automapper ProjectTo 中的递归 CTE 使用 EF Core 调用函数 Content将 [ { "commentId": "be02742a-9170-4335-afe7-3c7c22684424", "content": "Hello World!", "postId": "69f3ca3a-66fc-4142-873d-01e9

如何解决EF Core + Automapper ProjectTo 中的递归 CTE 使用 EF Core 调用函数 Content将 [ { "commentId": "be02742a-9170-4335-afe7-3c7c22684424", "content": "Hello World!", "postId": "69f3ca3a-66fc-4142-873d-01e9

在我的项目中,我有 structlogComment 类型:

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

我有以下递归 CTE,封装在表值函数中:

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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?