Как использовать группирование, различение и подсчет вместе в linq? - PullRequest
2 голосов
/ 19 октября 2011

У меня есть таблица ActivityLog со строкой для каждого попадания на каждой странице в веб-приложении.Таблица имеет следующие соответствующие поля: PageTitle, UserName, ActivityDate.Я хотел бы добавить страницу истории использования с GridView, которая имеет следующие столбцы: Заголовок страницы, # Хиты, # Уникальные пользователи.Таким образом, для каждой страницы в приложении мы показываем общее количество посещений и количество уникальных пользователей, попавших на эту страницу.

Я попробовал следующий 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 попадание на свою отдельную страницу (пользователь1 нажимает страницу 1, пользователь2 нажимает страницу 2 и пользователь 3 нажимает страницу 3), все три строки в моей таблице показывают 3 для столбца NumUniqueUsers, даже если они должны отображать1.

Есть предложения?

Спасибо, Крис

EDIT - Добавление сгенерированного 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 ]

1 голос
/ 19 октября 2011

"3 пользователя, у каждого по 1 удару на каждой из 3 страниц"

Я понимаю, что это означает, что ваш журнал выглядит так:

  • Пользователь1 - Page1
  • Пользователь1 - Страница2
  • Пользователь1 - Страница3
  • Пользователь2 - Страница1
  • Пользователь2 - Страница2
  • Пользователь2 - Страница3
  • Пользователь3 - Страница1
  • Пользователь3 - Страница2
  • Пользователь3 - Страница3

При таком сценарии на каждой странице действительно есть 3 уникальных пользователя, поэтому ваш код правильный

0 голосов
/ 19 октября 2011

Трудно сказать, где этот DISTINCT теряется.Возможно, LinqToSql отбрасывает его при переводе запросов.Просмотр сгенерированного sql подтвердит.

Если Distinct неожиданно отбрасывается LinqToSql, вот еще один способ написать эту часть запроса.

NumUniqueUsers = pageGroup.GroupBy(x => x.UserName).Count()
0 голосов
/ 19 октября 2011

Попробуйте добавить этот метод расширения:

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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...