如何在linq中使用分组,区分和计数?

时间:2011-10-19 14:13:49

标签: c# .net linq linq-to-sql

我有一个ActivityLog表,每个网页应用中的每个网页都有一行。该表具有以下相关字段:PageTitle,UserName,ActivityDate。我想添加一个带有GridView的Usage History页面,其中包含以下列:Page Title,#Hits,#Unique Users。因此,对于应用中的每个页面,我们都会显示点击总数以及点击该页面的唯一身份用户数。

我尝试了以下linq,从我在搜索中收集到的内容,应该可以工作:

var ual = (from activityLog in linqMetaData.UserActivityLog
           group activityLog by activityLog.PageTitle into pageGroup
           select new PageUsageStatistics()
           {
               PageTitle = pageGroup.Key,
               NumHits = pageGroup.Count(),
               NumUniqueUsers = pageGroup.Select(x => x.UserName).Distinct().Count()
           });

NumHits回复了预期的数字;但是,NumUniqueUsers将返回具有命中数的唯一总用户数,而不是每页的计数。因此,如果我有3个用户,每个用户在他们自己的不同页面上有1个点击(User1点击Page1,User2点击Page2,User3点击Page3),我表中的所有三行都显示3个NumUniqueUsers列,即使他们应该显示1.

有什么建议吗?

谢谢, 克里斯

编辑 - 添加生成的SQL:

SELECT [LPA_L1].[PageName], 
       [LPA_L1].[NumHits], 
       [LPA_L1].[NumUniqueUsers] 
FROM 
    (SELECT [LPA_L2].[PageTitle] AS [PageName], 
            [LPA_L2].[LPAV_] AS [NumHits], 
            (SELECT COUNT(*) AS [LPAV_] 
             FROM 
                 (SELECT DISTINCT [LPA_L2].[UserPrincipleName] 
                  FROM [USIC].[dbo].[UserActivityLog]  [LPA_L2]  
                 ) [LPA_L3]) AS [NumUniqueUsers] 
     FROM 
         (SELECT [LPLA_1].[PageTitle], 
                 COUNT(*) AS [LPAV_] 
          FROM [USIC].[dbo].[UserActivityLog]  [LPLA_1]   
          GROUP BY [LPLA_1].[PageTitle]
         ) [LPA_L2]
    ) [LPA_L1] 
ORDER BY [LPA_L1].[PageName] ASC

3 个答案:

答案 0 :(得分:1)

“3个用户,每个页面分别有1个点击”

我将其解释为您的日志的含义:

  • User1 - Page1
  • User1 - Page2
  • User1 - Page3
  • User2 - Page1
  • User2 - Page2
  • User2 - Page3
  • User3 - Page1
  • User3 - Page2
  • User3 - Page3

在这种情况下,每个页面确实有3个唯一用户,因此您的代码是正确的

答案 1 :(得分:0)

尝试添加此扩展方法:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> knownKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (knownKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

并像这样使用它:

NumUniqueUsers = pageGroup.DistinctBy(x => x.UserName).Count();

答案 2 :(得分:0)

很难说DISTINCT在哪里迷路了。也许LinqToSql在查询翻译中丢弃了它。查看生成的sql将确认。

如果LinqToSql正在(意外地)删除了Distinct,那么这是编写该部分查询的另一种方法。

NumUniqueUsers = pageGroup.GroupBy(x => x.UserName).Count()