1

I have the following data schema:

SQL Server data diagram

With the following LINQ query:

var profiles = (
    from p in context.BusinessProfiles
    join u in context.Users on p.UserId equals u.Id
    join addr in context.BusinessAddress on p.ProfileId equals addr.ProfileId into addrj
    from addr in addrj.DefaultIfEmpty()
    join pa in context.BusinessProfileActivities on p.ProfileId equals pa.ProfileId into paj
    from paIfNull in paj.DefaultIfEmpty()
    where p.ProfileId >= 137 && p.ProfileId <= 139
    group new { p, u, addr, paIfNull } 
        by new {
            p.ProfileId,
            p.CompanyName,
            p.Email,
            UserEmail = u.Email,
            addr.City, addr.Region,
            addr.Country,
            ActivityProfileId = paIfNull.ProfileId } 
        into pg
    select new {
        pg.Key.ProfileId,
        pg.Key.CompanyName,
        Email = pg.Key.Email ?? pg.Key.UserEmail,
        pg.Key.City,
        pg.Key.Region,
        pg.Key.Country,
        MatchingActivities = pg.Key.ActivityProfileId > 0 ? pg.Count() : 0
    } into result
    orderby result.MatchingActivities descending
    select result
);

Which results with:

Linq results

This result is corrent (ProfileId 137 has 0 activities, 138 has 1 and 139 has 2), but it produces the following SQL:

SELECT [b].[ProfileId], [b].[CompanyName], COALESCE([b].[Email], [a].[Email]) AS [Email], [b0].[City], [b0].[Region], [b0].[Country], 
    CASE WHEN [b1].[ProfileId] > CAST(0 AS bigint) THEN COUNT(*)
    ELSE 0
END AS [MatchingActivities]
FROM [BusinessProfiles] AS [b]
INNER JOIN [AspNetUsers] AS [a] ON [b].[UserId] = [a].[Id]
LEFT JOIN [BusinessAddress] AS [b0] ON [b].[ProfileId] = [b0].[ProfileId]
LEFT JOIN [BusinessProfileActivities] AS [b1] ON [b].[ProfileId] = [b1].[ProfileId]
WHERE ([b].[ProfileId] >= CAST(137 AS bigint)) AND ([b].[ProfileId] <= CAST(139 AS bigint))
GROUP BY [b].[ProfileId], [b].[CompanyName], [b].[Email], [a].[Email], [b0].[City], [b0].[Region], [b0].[Country], [b1].[ProfileId]
ORDER BY CASE
    WHEN [b1].[ProfileId] > CAST(0 AS bigint) THEN COUNT(*)
    ELSE 0
END DESC

In SQL, I can avoid both CASE WHEN if I use COUNT([b1].[ProfileId]) like this:

SELECT [b].[ProfileId], [b].[CompanyName], COALESCE([b].[Email], [a].[Email]) AS [Email], [b0].[City], [b0].[Region], [b0].[Country], 
    COUNT([b1].[ProfileId]) AS [MatchingActivities]
FROM [BusinessProfiles] AS [b]
INNER JOIN [AspNetUsers] AS [a] ON [b].[UserId] = [a].[Id]
LEFT JOIN [BusinessAddress] AS [b0] ON [b].[ProfileId] = [b0].[ProfileId]
LEFT JOIN [BusinessProfileActivities] AS [b1] ON [b].[ProfileId] = [b1].[ProfileId]
WHERE ([b].[ProfileId] >= CAST(137 AS bigint)) AND ([b].[ProfileId] <= CAST(139 AS bigint))
GROUP BY [b].[ProfileId], [b].[CompanyName], [b].[Email], [a].[Email], [b0].[City], [b0].[Region], [b0].[Country], [b1].[ProfileId]
ORDER BY [MatchingActivities] DESC

My question is, how can I count by grouped ActivityProfileId = paIfNull.ProfileId using LINQ and get EF to generate the above SQL?

I have tried so many variations resulting mostly in EF to SQL errors.

MatchingActivities = pg.Count(t => t.ActivityProfileId!= 0)
MatchingActivities = pg.Select(t => t.paIfNull.ProfileId).Distinct().Count(),
MatchingActivities = pg.Count(t => t.paIfNull != null),

All result in errors like System.InvalidOperationException: The LINQ expression ... could not be translated. or getting MatchingActivities as 1 instead of 0.

Related Q/A:

LINQ Count returning 1 instead of zero for an empty group

Group by in LINQ

How to write left join, group by and average in c# entity framework Linq

Christos Lytras
  • 36,310
  • 4
  • 80
  • 113

1 Answers1

1

In short you can't! EF Core still doesn't support that.

See this: https://github.com/dotnet/efcore/issues/17376

And also See: https://stackoverflow.com/a/61878332/9212040

Arman Ebrahimpour
  • 4,252
  • 1
  • 14
  • 46