2011-10-19 36 views
2

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

我曾尝试以下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 
+1

老实说,我没有看到任何错误的代码。 –

+0

哈哈,我也不会!我无法弄清楚为什么它显示3而不是1为独特的用户! – RebelScum

+0

你能告诉我们生成的sql吗? –

回答

1

“3个用户,每个有1次命中每3页”

我解释,由于这意味着你的日志看起来像:

  • User1 - Page1
  • 用户1 - 2页
  • 用户1 - 第3页
  • 用户2 - 第1页
  • 用户2 - 第2页
  • 用户2 - 第3页
  • 用户3 - 第1页
  • 用户3 - 第2页
  • 用户3 - 第3页

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

+0

对不起,那还不清楚。我的意思是,每个用户都有自己独特的页面。所以它是:User1 - Page1; User2 - Page2; User3 - Page3。我将修改原始帖子。 – RebelScum

+0

不过,这里的代码看起来很好。所以我会做两件事......首先,放入一个断点并检查pageGroup以查看它实际包含的内容。如果它不包含您期望的内容(3个条目,每个用户1个),那么问题可以追溯到具有不良数据的activityLog。否则,问题可以追溯到Distinct无法正确比较UserName值。你可以通过使用Distinct中的其他重载来解决这个问题,它可以让你传入一个自定义比较器。 –

+0

我试着把一个断点放进去,它不会停止在查询中; VS将断点放在整个查询中,然后当你进入它时,它停在DataSource getter上,当你试图进入它时,它跳过了linq查询。我无法让它在查询中停下来。对此有何建议? – RebelScum

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(); 
+0

这不会转换为SQL。 –

+0

你是说这不能用于LINQ to SQL? –

+0

没有办法将“新HashSet ()”放入数据库。由.NET编译的方法不能转换为只有sql的表达式树,而只能转换成某些表达式树。 –

0

很难说哪里是DISTINCT迷路。也许LinqToSql将它放在查询翻译中。看着生成的SQL将确认。

如果Distinct正在通过LinqToSql获取(意外),这是另一种编写该部分查询的方法。

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

我试过这个,得到了“无法投射'SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.QueryExpression'类型的对象来输入'SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.SetReferenceExpression'。” – RebelScum

+0

现在我已经添加了生成的SQL,它看起来像Distinct不会迷路,但它应用于整个表格,而不是分组部分。 – RebelScum