Порядок Entity Framework Core 2.2 оценивается локально - PullRequest
0 голосов
/ 26 декабря 2018

У меня есть этот полусложный запрос, который подсчитывает количество постов за последние 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)).

Что я делаю не так?

1 Ответ

0 голосов
/ 26 декабря 2018

Что произойдет, если вы объедините суть votedPosts в запросе, чтобы не дублировать join на posts?

var bestPost = (
    from post in dbContext.Posts
    join vote in dbContext.Votes on post.PostId equals vote.PostId into votej
    let voteTotalRating = votej.Sum(pv => pv.Sign)
    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 voteTotalRating 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 = voteTotalRating
    }).FirstOrDefault();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...