Linq: количество групп строк, включая 0 для пропущенных строк - PullRequest
4 голосов
/ 07 октября 2011

Я хотел бы обобщить список действий по количеству вхождений по дням за последнюю неделю, используя Linq to Entities. Например, допустим, у меня есть такие данные в моей базе данных:

Id | Date
1  | 2011-09-30 0:00:0
2  | 2011-10-02 0:00:00  
3  | 2011-10-02 0:00:00
4  | 2011-10-02 0:00:00
5  | 2011-10-04 0:00:00
6  | 2011-10-04 1:30:30
7  | 2011-10-04 0:00:00
8  | 2011-10-06 0:00:00

и, скажем, сегодняшняя дата 2011-10-07

Я хотел бы сгенерировать следующее:

Date        | Count
2011-10-01  | 0
2011-10-02  | 3
2011-10-03  | 0
2011-10-04  | 3
2011-10-05  | 0
2011-10-06  | 1
2011-10-07  | 0

Вот пример техники, которую я могу использовать для группировки вхождений по дате, но я пропускаю нули.

// Using Linq to Objects for demonstration purpose only
var activities = new List<Activity>();
activities.Add(new Activity { Id = 1, Date = new DateTime(2011, 9, 30)});
activities.Add(new Activity { Id = 2, Date = new DateTime(2011, 10, 2)});
activities.Add(new Activity { Id = 3, Date = new DateTime(2011, 10, 2)});
activities.Add(new Activity { Id = 4, Date = new DateTime(2011, 10, 2)});
activities.Add(new Activity { Id = 5, Date = new DateTime(2011, 10, 4)});
activities.Add(new Activity { Id = 6, Date = new DateTime(2011, 10, 4, 1, 30, 30) });
activities.Add(new Activity { Id = 7, Date = new DateTime(2011, 10, 4)});
activities.Add(new Activity { Id = 8, Date = new DateTime(2011, 10, 6)});

var data = (from a in activities
            group a by a.Date.Date into g
            where g.Key > DateTime.UtcNow.AddDays(-7)
            select new {
                Date = g.Key,
                Count = g.Count()
            }).ToList();

Вот результат:

Date        | Count
2011-10-02  | 3
2011-10-04  | 3
2011-10-06  | 1

Кто-нибудь знает, как я могу включить недостающие нули, используя Linq to Entities? Я всегда мог бы перечислить результаты, как только они будут в памяти, но было бы неплохо получить их непосредственно из базы данных.

Ответы [ 3 ]

2 голосов
/ 07 октября 2011

Может быть так же легко сгенерировать цикл, поскольку данные еще не доступны в базе данных, и сделать это через LINQ будет сложно:

var firstDate = data.Min(d => d.Date).AddDays(-1);
var lastDate = data.Max(d => d.Date).AddDays(1);

for (var date = firstDate; date <= lastDate; date = date.AddDays(1))
    if (!data.Exists(d => d.Date == date))
        data.Add(new { Date = date, Count = 0 });

data = data.OrderBy(d => d.Date);
// do something with data

Если ваш набор данных действительно не будет,очень большой, этот запрос в памяти и корректировка списка будут арахисами по сравнению со временем, которое требуется для запроса базы данных.

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

Вы можете сгенерировать массив дат, учитывая начальное значение и зная количество дней, которые вы хотите вернуть. Здесь я жестко его кодирую, но вы можете вытащить его из списка действий, используя Мин. И Макс. И определив соответственно начальное значение и количество дней.

var allDays = Enumerable.Range(0,7).Select (i => new DateTime(2011,9,30).AddDays(i) );

Как только вы это сделаете, вы можете использовать подвыбор или объединение для объединения:

var data = (from d in allDays
            select new {
                Date = d,
                Count = activities.Count (a => a.Date.Date == d)
            }).ToList();
0 голосов
/ 07 октября 2011

Если вы хотите получить результат в одном запросе linq, вам придется выполнить эту операцию в базе данных. Таким образом, вы должны иметь все дни в вашей базе данных , даже если они имеют 0 действий . Это означает, что вы должны создать новую таблицу.

В вашем сценарии я бы создал таблицу календаря и внешнее объединение для этой таблицы, чтобы получить дни с 0 действиями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...