简体   繁体   中英

Converting a SQL server query to EF Core LINQ

I am currently trying to convert an existing SQL server query to EF Core. The goal is to get all users and get their latest order date-time and latest support request date-time. I want to ensure users are returned even if they don't have an order yet or a support request yet. If they have not placed an order, the column for "latest order date-time" should be NULL. If they have not filed a support request, the column for "latest support request date-time" should be NULL.

The outputted columns should be: Id, Name, Email, LatestOrderDateTime, LatestSupportRequestDateTime

Here is my working SQL server query:

SELECT [User].[Id], [User].[Name], [User].[Email], MAX([Order].[DateTime]) as LatestOrderDateTime, MAX([SupportRequest].[DateTime]) as LatestSupportRequestDateTime FROM [User]
LEFT JOIN [Order] on [User].[Id] = [Order].[UserId]
LEFT JOIN [SupportRequest] on [User].[Id] = [SupportRequest].[ConsumerId]
GROUP BY [User].[Id], [User].[Name], [User].[Email]
ORDER BY [User].[Id]

This is what I've tried, however it does not evaluate on the server:

await this.context.User
    .GroupBy(u => new { u.Id, u.Name, u.Email })
    .Select(g => new
    {
        id = g.Key.Id,
        name = g.Key.Name,
        email = g.Key.Email,
        lastOrderDateTime = g.Max(o => o.Orders.Select(o => o.DateTime)),
        lastSupportRequestDateTime = g.Max(o => o.SupportRequests.Select(s => s.DateTime)),
    })
    .OrderBy(c => c.id)
    .ToListAsync();

I just want to convert this query to EF core (where the query DOES NOT get evaluated locally).

If you could do it in method syntax, that'd be great, but no worries if not since I can convert it with JetBrains Rider.

Thank you so much for your help!

I just want to convert this query to EF core (where the query DOES NOT get evaluated locally).

Can not be done, use EntityFramework 6.4, not core, if you want this.

The SQL generation in current EntityFramework (and I mean current up to the nightly builds of veryion 5) is EXTREMELY Limited in the SQL it can generate, combined with what looks like utter ignorance to even accept that fact from the team (which reminds me of the times of EntityFramework 2 and 3 until that team started being serious about LINQ in their version 4).

If it tells you it can not generate this as SQL then your only 2 choises are:

  • Use EntityFramework 6.4 (which works in dotnetcore 3.1) and get server side execution
  • Open a bug report, HOPE someone picks it up and then either wait until November for the release of version 5 OR - once it possibly is fixed - work with nightly builds until then.

This is not a syntax issue. They deactivated client evaluation of SQL and their SQL generator is not able to handle a LOT of standard cases. Given you do not want the first (which is what we do at the moment), their feature set just means it can not be done.

You could try to explicitly spell out the left joins in Linq (left join syntax is a bit un-intuitive iirc so it may take some doing to sort it out).

You can find more information at:

https://docs.microsoft.com/en-us/dotnet/csharp/linq/perform-left-outer-joins

The way your Linq is set up specifically asks for object linking, which is why it happens client side. I believe what you're trying to do has a solution in EF Core.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM