У меня есть запрос, который я пытаюсь перенести с SQL (T-SQL) на LINQ-to-Entities 4.0 (C #). Результирующий набор содержит комбинацию стандартных «строк сведений», а также совокупную «статистическую» информацию.
В исходном SQL использовался стандартный выбор, соединенный слева с информацией о совокупности, подобный этому:
SELECT
UserId,
Name,
Email,
ISNULL(Stats.TotalPosts, 0) as TotalPosts,
Stats.LastPost
FROM Users
LEFT OUTER JOIN
(
SELECT UserId, COUNT(*) as TotalPosts, MAX(DatePosted) as LastPost
FROM Articles
GROUP BY UserId
) as Stats ON Stats.UserId = Users.UserID
По соображениям производительности вместо подзапросов в операторе SELECT используется левое объединение - возвращается более одной агрегированной статистики (общее количество сообщений и дата последнего сообщения)
У меня был некоторый частичный успех при преобразовании его в запрос LINQ-to-Entities в C # 4.0, но я не совсем уверен, как соединение должно связываться с оператором группы. Я думаю, что думаю об этом с точки зрения SQL и неправильно использую LINQ.
Мне удалось разбить статистику на отдельный запрос:
var stats =
(
from a in entities.Articles
group a by a.UserId into g
select new
{
UserId = g.Key,
TotalPosts = g.Count(),
LastUpdated = g.Max(i => i.DatePosted)
}
);
var query =
(
from u in entities.Users
join s in stats on u.UserId equals s.UserId
orderby u.Name
select new UserListing()
{
UserId = u.UserId,
Name = u.Name,
Email = u.Email,
TotalPosts = s.TotalPosts,
LastUpdated = s.LastUpdated
}
);
К сожалению, объединение, используемое в запросе LINQ, отфильтровывает всех пользователей, которые не отправили ни одной статьи.
Переключение на эквивалент внешнего соединения путем включения DefaultIfEmpty вызывает другие проблемы - я могу только вернуть «null» для TotalPosts вместо 0. Даже с «TotalPosts = (s.TotalPosts == null)? msgstr "в выборе выбрасывается исключение, если свойство TotalPosts не может иметь значение null.
Каковы наилучшие практики для объединения строк сведений и агрегирования информации таким образом?
Спасибо!