.Net 5 Entity Framework 从涉及 FK 1:M 关系的查询中删除不必要的调用

.Net 5 Entity Framework removing unneccessary calls from Query involving FK 1:M relationship

我有以下 2 个 DTO,用于 return API 中的信息,以便过滤掉我不希望客户端能够查看的字段

public record CommentDto
{
    public int? CommentId { get; set; }
    public string AuthorUid { get; set; }
    public string Text { get; set; }
    public int? ParentCommentId { get; set; }
    public string CommentPn { get; set; }
    public virtual UserDto User { get; set; }
}

public record UserDto
{
    public string Uid { get; set; }
    public string Username { get; set; }
}

我正在使用以下查询 postgres 数据库:

            var comments = await dbSet.
            Where(c => c.commentPn == sentPn)
           .Select(c => new CommentDto
            {
                CommentId = c.CommentId,
                CommentPn = c.CommentPn,
                AuthorUid = c.AuthorUid,
                Text = c.Text,
                ParentCommentId = c.ParentCommentId,
                User = new UserDto
                {
                    Username = dbSet.Select(u => u.User.Username).Single(),
                    Uid = dbSet.Select(u => u.User.Uid).Single()
                },
            }).ToListAsync();

虽然这有效并且 return 编辑了正确的数据,但我注意到查询中包含了我认为不必要的调用。

  SELECT d1.comment_id AS "CommentId", d1.comment_pn AS "CommentNiin", d1.author_uid AS "AuthorUid", d1.comment_text AS "Text", d1.parent_comment_id AS "ParentCommentId", (
      SELECT u.username
      FROM database_item_comments AS d
      INNER JOIN users AS u ON d.author_uid = u.uid
      LIMIT 1) AS "Username", (
      SELECT u0.uid
      FROM database_item_comments AS d0
      INNER JOIN users AS u0 ON d0.author_uid = u0.uid
      LIMIT 1) AS "Uid"
  FROM database_item_comments AS d1

我知道这是因为我检索用户值的方式效率极低,完成此查询的正确方法是仅对用户进行一次调用 table?

最好直接查询评论 table,并 return 在没有 DTO 的情况下访问完整的评论实体,而不必映射变量,同时为评论创建 UserDto 并映射值

您的 Comment 实体应该引用一个 User 实体,它将看到您的查询更正为:

        var comments = await dbSet.
        Where(c => c.commentPn == sentPn)
       .Select(c => new CommentDto
        {
            CommentId = c.CommentId,
            CommentPn = c.CommentPn,
            AuthorUid = c.AuthorUid,
            Text = c.Text,
            ParentCommentId = c.ParentCommentId,
            User = new UserDto 
            {
                UId = c.User.UId,
                Username = c.User.Username
            });
        }).ToListAsync();

如果您在数据库中有多个评论来填充用户 DTO,您的示例可能会失败,您实际上告诉它加载 所有 评论(DbSet.Select)获取用户并期望通过 Single() 只有 1 个结果。然后是你执行两次的事实,一次是 select ID,然后是 select 名字。