EF LINQ Count по сгруппированному полю - PullRequest
1 голос
/ 18 июня 2020

У меня есть следующая схема данных:

SQL Server data diagram

Со следующим запросом LINQ:

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

Результат:

Linq results

Этот результат является соответствующим (ProfileId 137 имеет 0 действий, 138 имеет 1 и 139 имеет 2), но он производит следующее 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

В SQL, я могу избежать обоих CASE WHEN, если я использую COUNT([b1].[ProfileId]) вот так:

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

Мой вопрос в том, как я могу посчитать по сгруппированным ActivityProfileId = paIfNull.ProfileId с помощью LINQ и получить EF для генерации вышеуказанного SQL?

Я пробовал так много вариантов, что в основном приводило к ошибкам EF до SQL .

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

Все приводят к ошибкам, например System.InvalidOperationException: The LINQ expression ... could not be translated. или получению MatchingActivities как 1 вместо 0.

Связанные вопросы / ответы:

LINQ Count, возвращающий 1 вместо нуля для пустой группы

Группировать по в LINQ

Как запись левого соединения, группировки и среднего значения в c# структуре сущностей Linq

1 Ответ

1 голос
/ 18 июня 2020

Короче нельзя! EF Core по-прежнему не поддерживает это.

См. Это: https://github.com/dotnet/efcore/issues/17376

А также см .: { ссылка }

...