选择 LINQ 到实体查询中记录的聚合(分组)统计信息
我有一个查询正在尝试从 SQL (T-SQL) 移植到 LINQ-to-Entities 4.0 (C#)。结果集包含标准“详细信息行”以及聚合“统计”信息的组合。
原始 SQL 使用标准 select 左连接到聚合信息,类似于:
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 语句中使用左连接而不是子查询 - 返回多个聚合统计信息(帖子总数和发布日期)最后一篇文章)
我已经部分成功地将其转换为 C# 4.0 中的 LINQ-to-Entities 查询,但我不完全确定联接应如何与组语句结合起来。我想我正在从 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 切换到等效的外连接会导致其他问题 - 我只能为 TotalPosts 返回“null”而不是 0。即使在“TotalPosts = (s.TotalPosts == null) ? 0 : s.TotalPosts”中select,除非 TotalPosts 属性可为空,否则将引发异常。
以这种方式组合详细信息行和聚合信息的最佳实践是什么?
谢谢!
I have a query I'm attempting to port from SQL (T-SQL) to LINQ-to-Entities 4.0 (C#). The result set contains a combination of standard "detail rows" as well as aggregate "statistic" information.
The original SQL used a standard select left-joined to the aggregate information, similar to this:
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
A left join is used rather than subqueries in the SELECT statement for performance reasons - more than one aggregate statistic is returned (total posts and the date of the last post)
I've had some partial success converting it to a LINQ-to-Entities query in C# 4.0, but I'm not entirely sure how the join should tie in with the group statement. I imagine I'm thinking about this in terms of SQL and not using LINQ correctly.
I had some success breaking out the statistics into a separate query:
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
}
);
Unfortunately, the join used in the LINQ query filters out all users who have not submitted any articles.
Switching to the equivalent of an outer join by including DefaultIfEmpty causes other problems - I can only return "null" for TotalPosts instead of 0. Even with "TotalPosts = (s.TotalPosts == null) ? 0 : s.TotalPosts" in the select, an exception is thrown unless the TotalPosts property is nullable.
What are the best practices for combining detail rows and aggregate information in this way?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
试试这个:
Try this:
您可以选择的一种方法是确保
stats
查询中的相应属性可以为空。如果可能的话,LINQ-to-entities 将进行必要的调整以使这项工作正常进行。然后照常执行左外连接。One option you have is to make sure that the appropriate properties in the
stats
query are nullable. LINQ-to-entities will make the necessary adjustments to make this work if at all possible. Then perform the left outer join as usual.要获得外部联接,您需要使用
DefaultIfEmpty
。要解决 null 问题,您可以尝试
,或者如果 s.TotalPosts 不知何故没有显示为
int?
您可以尝试像To get an outer join you need to use
DefaultIfEmpty
.To solve the null issue you might try
or if s.TotalPosts somehow does not turn up as
int?
you might try hacks like