[英]Simplify Entity Framework Core query
I do not understand how to simplify this request我不明白如何简化此请求
var dialogs = await dbContext.UsersDialogs
.AsNoTracking()
.Where(x => x.UserId == userId)
.Select(x => new DialogModel
{
Id = x.DialogId,
Login = x.Dialog.Name,
Image = x.User.FacialImage,
IsConfirm = x.Dialog.Messages.OrderBy(x => x.DateCreate).LastOrDefault().IsRead,
DateTime = x.Dialog.Messages.OrderBy(x => x.DateCreate).LastOrDefault().DateCreate,
LastMessage = x.Dialog.Messages.OrderBy(x => x.DateCreate).LastOrDefault().Content,
LastUserId = x.Dialog.Messages.OrderBy(x => x.DateCreate).LastOrDefault().UserId
})
.ToListAsync();
It will transform it into a request like this它会将其转换为这样的请求
SELECT [u].[DialogId] AS [Id], [d].[Name] AS [Login], [u0].[FacialImage] AS [Image], (
SELECT TOP(1) [m].[IsRead]
FROM [Messages] AS [m]
WHERE [d].[Id] = [m].[DialogId]
ORDER BY [m].[DateCreate] DESC) AS [IsConfirm], (
SELECT TOP(1) [m0].[DateCreate]
FROM [Messages] AS [m0]
WHERE [d].[Id] = [m0].[DialogId]
ORDER BY [m0].[DateCreate] DESC) AS [DateTime], (
SELECT TOP(1) [m1].[Content]
FROM [Messages] AS [m1]
WHERE [d].[Id] = [m1].[DialogId]
ORDER BY [m1].[DateCreate] DESC) AS [LastMessage], (
SELECT TOP(1) [m2].[UserId]
FROM [Messages] AS [m2]
WHERE [d].[Id] = [m2].[DialogId]
ORDER BY [m2].[DateCreate] DESC) AS [LastUserId]
FROM [UsersDialogs] AS [u]
INNER JOIN [Dialogs] AS [d] ON [u].[DialogId] = [d].[Id]
INNER JOIN [Users] AS [u0] ON [u].[UserId] = [u0].[Id]
WHERE [u].[UserId] = @__userId_0
Сan I somehow optimize it? Сan我以某种方式优化它? I don't want to use a SQL query because Linq seems more convenient to me.
我不想使用 SQL 查询,因为 Linq 对我来说似乎更方便。
You have created query which is translated directly to the same SQL.您已创建直接转换为相同 SQL 的查询。 You can omit repeating queries by additional
Select
.您可以通过额外的
Select
省略重复查询。 Also AsNoTracking
is not needed - EF Core do not tack custom entities.也不需要
AsNoTracking
- EF Core 不添加自定义实体。
var dialogs = await dbContext.UsersDialogs
.Where(x => x.UserId == userId)
.Select(x => new
{
UserDialog = x,
LastMessage = x.Dialog.Messages.OrderByDescending(x => x.DateCreate).FirstOrDefault()
})
.Select(x => new DialogModel
{
Id = x.UserDialog.DialogId,
Login = x.UserDialog.Dialog.Name,
Image = x.UserDialog.User.FacialImage,
IsConfirm = x.LastMessage.IsRead,
DateTime = x.LastMessage.DateCreate,
LastMessage = x.LastMessage.Content,
LastUserId = x.LastMessage.UserId
})
.ToListAsync();
As far as the LINQ query is concerned, you can simplify it by using query syntax and let
:就 LINQ 查询而言,您可以使用查询语法来简化它,
let
:
from d in dbContext.UsersDialogs
where d.UserId == userId
let lastMessage = d.Dialog.Messages.OrderBy(d => d.DateCreate).LastOrDefault()
select new DialogModel
{
Id = d.DialogId,
Login = d.Dialog.Name,
Image = d.User.FacialImage,
IsConfirm = lastMessage.IsRead,
DateTime = lastMessage.DateCreate,
LastMessage = lastMessage.Content,
LastUserId = lastMessage.UserId
}
But that doesn't optimize the SQL query.但这并没有优化 SQL 查询。 EF generates the same subquery over and over again for each field from the Messages table.
EF 为 Messages 表中的每个字段一遍又一遍地生成相同的子查询。 In SQL Server, the query plan doesn't optimize these subqueries away into one branch.
在 SQL 服务器中,查询计划不会将这些子查询优化到一个分支中。
If you really want to optimize the SQL query you have to do something like this:如果您真的想优化 SQL 查询,您必须执行以下操作:
(
from d in dbContext.UsersDialogs
where d.UserId == userId
select new
{
Id = d.DialogId,
Login = d.Dialog.Name,
Image = d.User.FacialImage,
LastMessage = (from d.Dialog.Messages
orderby d.DateCreate
select new
{
IsConfirm = d.IsRead
d.DateCreate,
d.Content,
d.UserId
}).LastOrDefault()
}
).AsEnumerable()
.Select(x => new DialogModel
{
Id = x.DialogId,
Login = x.Dialog.Name,
Image = x.User.FacialImage,
LastMessage.IsConfirm,
LastMessage.DateCreate,
LastMessage.Content,
LastMessage.UserId
})
By adding AsEnumerable
, which forces client-side evaluation of the last part of the query, EF generates a query with one subquery that uses the ROW_NUMBER() OVER
function to get the last message only once.通过添加
AsEnumerable
,强制客户端对查询的最后一部分进行评估,EF 生成一个带有一个子查询的查询,该子查询使用ROW_NUMBER() OVER
function 只获取最后一条消息一次。 But of course it's quite a hassle to do this.但是,这样做当然很麻烦。 But it may be necessary if the first query suffer considerable performance hits.
但是,如果第一个查询遭受相当大的性能影响,则可能有必要。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.