C# Linq:为缺少的行计数包括0的行组

C# Linq:为缺少的行计数包括0的行组,c#,linq,entity-framework,linq-to-entities,C#,Linq,Entity Framework,Linq To Entities,我想使用LINQtoEntities将一个活动列表总结为上周每天发生的事件数。例如,假设我的数据库中有这样的数据: 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-

我想使用LINQtoEntities将一个活动列表总结为上周每天发生的事件数。例如,假设我的数据库中有这样的数据:

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

有人知道如何使用Linq to实体包含缺少的零吗?在内存中保存结果后,我总是可以枚举结果,但直接从数据库中获取结果会更好。

如果您想在一个linq查询中获得结果,则必须在数据库中执行此操作。因此,您必须拥有数据库中的所有日期,即使它们的活动为0。这意味着您必须创建一个新表


在您的场景中,我将创建一个日历表,并在该表上进行外部联接,以获取具有0个活动的日期。

由于数据库中尚未提供数据,因此使用循环生成该日历表可能同样容易,而通过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
var firstDate=data.Min(d=>d.Date.AddDays(-1);
var lastDate=data.Max(d=>d.Date).AddDays(1);
对于(变量日期=第一个日期;日期d.日期==日期))
data.Add(新的{Date=Date,Count=0});
data=data.OrderBy(d=>d.Date);
//处理数据

除非您的数据集非常非常大,否则与数据库请求所需的时间相比,此内存中查询和调整列表将是微不足道的。

您可以在给定开始值并知道要返回的天数的情况下生成日期数组。我在这里对它进行硬编码,但是您可以使用Min和Max从活动列表中提取它,并相应地确定开始值和天数

var allDays = Enumerable.Range(0,7).Select (i => new DateTime(2011,9,30).AddDays(i) );
一旦完成此操作,您可以使用subselect或join进行聚合:

var data = (from d in allDays
            select new {
                Date = d,
                Count = activities.Count (a => a.Date.Date == d)
            }).ToList();

直接从数据库中获取?它首先不在数据库中,因为您正在生成丢失的日期。只使用for循环可能会更简单、更有效。
var data = (from d in allDays
            select new {
                Date = d,
                Count = activities.Count (a => a.Date.Date == d)
            }).ToList();