I have the following data schema:
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:
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
How to write left join, group by and average in c# entity framework Linq