У меня есть этот полусложный запрос, который подсчитывает количество постов за последние 7 дней с наибольшим количеством голосов:
var fromDate = dateTimeService.Now.Add(-interval);
var votedPosts =
from vote in dbContext.Votes
join post in dbContext.Posts on vote.PostId equals post.PostId
group new {vote.Sign, post.PostId} by post.PostId
into postVotes
select new {
PostId = postVotes.Key,
TotalRating = postVotes.Sum(pv => pv.Sign)
};
var bestPost = (
from post in dbContext.Posts
join votedPost in votedPosts on post.PostId equals votedPost.PostId
join room in dbContext.Rooms on post.RoomId equals room.RoomId
join game in dbContext.Modules on room.ModuleId equals game.ModuleId
where room.RoomAccess == RoomAccessType.Open && post.CreateDate > fromDate
orderby votedPost.TotalRating descending,
post.CreateDate descending
select new BestPost
{
UserId = post.UserId,
ModuleId = game.ModuleId,
ModuleTitle = game.Title,
PostId = post.PostId,
PostText = post.Text,
PostCommentary = post.Commentary,
PostCreateDate = post.CreateDate,
TotalRating = bestPost.TotalRating
}).FirstOrDefault();
Здесь я пытаюсь сгруппировать голоса пользователей по PostId
, суммируяоценка их голосов по полю Sign
(может быть -1, 0 или 1), затем объедините его с некоторыми дополнительными данными, такими как идентификатор игры / заголовок и тексты постов, отфильтруйте непубличные или слишком старые посты, затем упорядочите их по рангуи затем по дате создания, затем сопоставьте его с DTO и верните самый первый результат, если он присутствует.
Все поля здесь являются простыми основными типами: Vote.Sign
равно int
, Post.CreateDate
равно DateTime
все *Id
Guid
и Text/Title/Commentary
string
.
Я получаю предупреждение:
предупреждение: Microsoft.EntityFrameworkCore.Query [20500]
Выражение LINQ 'orderby [bestPost] .TotalRating desc' не может быть переведено и будет оценено локально.
warn: Microsoft.EntityFrameworkCore.Query [20500]
Возможно выражение LINQ 'FirstOrDefault ()'не переводится и будет оцениваться на месте.
Если я удаляю сортировку по TotalRating
и оставляю только сортировку CreateDate
, она работает нормально, создает правильный LIMIT
запрос.Но с TotalRating
запрос выглядит так:
SELECT
t."PostId", t."TotalRating", post."CreateDate" AS "PostCreateDate",
post."UserId", game."ModuleId", game."Title" AS "ModuleTitle",
post."PostId" AS "PostId0", post."Text" AS "PostText",
post."Commentary" AS "PostCommentary"
FROM
"Posts" AS post
INNER JOIN
(SELECT
post0."PostId", SUM(vote."Sign")::INT AS "TotalRating"
FROM
"Votes" AS vote
INNER JOIN
"Posts" AS post0 ON vote."PostId" = post0."PostId"
GROUP BY
post0."PostId") AS t ON post."PostId" = t."PostId"
INNER JOIN
"Rooms" AS room ON post."RoomId" = room."RoomId"
INNER JOIN
"Modules" AS game ON room."ModuleId" = game."ModuleId"
WHERE
(room."RoomAccess" = 0) AND (post."CreateDate" > @__fromDate_0)
И выглядит довольно плохо, если его вычислить во время выполнения dotnet.
Я попытался обернуть результат в другой select from
,но это не помоглоЯ также не могу выполнить группирование по всем столбцам, потому что тогда я не смогу агрегировать такие вещи, как ModuleId
, потому что EF Core 2.2 не поддерживает вещи group.FirstOrDefault
, а PostgreSQL не поддерживает max(uuid)
(в противном случае я мог быиспользуйте group.Max(g => g.ModuleId)
).
Что я делаю не так?