.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 名字。
我有以下 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 名字。