Entity Framework Core 2.2 orderby evaluated locally

c# entity-framework-core postgresql

Question

I have this semi-complex query that counts the most voted user post of the last 7 days:

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();

What I try to do here is to group user votes by PostId, sum the evaluations of their votes by field Sign (can be -1, 0 or 1), then join it with some additional data like game Id/Title and post texts, filter non-public or too old posts, then order it by rank and then by create date, then map it onto DTO and return the very first result if present.

All the fields here are simple basic types: the Vote.Sign is int, Post.CreateDate is DateTime, all the *Id are Guid and Text/Title/Commentary are string.

I get the warning:

warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'orderby [bestPost].TotalRating desc' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'FirstOrDefault()' could not be translated and will be evaluated locally.

If I remove the sort by TotalRating and only leave the CreateDate sorting, it works fine, creates proper LIMIT request. But with TotalRating the query looks like this:

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)

And it looks pretty bad to be calculated in dotnet runtime.

I tried to wrap the result in another select from, but it didn't help. I also cannot do the group by on all the columns because then I won't be able to aggregate things like ModuleId because EF Core 2.2 does not support the group.FirstOrDefault things and PostgreSQL does not support max(uuid) (otherwise I could use group.Max(g => g.ModuleId)).

What am I doing wrong?

1
0
12/26/2018 4:41:03 PM

Popular Answer

What happens if you combine the gist of votedPosts into the query so you don't duplicate the join on 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();
1
12/26/2018 7:42:35 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow