Linq DefaultValues on Join

时间:2013-07-19 16:32:48

标签: c# linq

我正在尝试在不同设备上获取过去30天内我的应用的总下载次数,我成功返回正确的查询,按天数分组并加入过去30天的可枚举。但是我无法按照自己的意愿格式化输出。让我先与LinqPad中的演示文稿分享查询

var last_days = (from idx in Enumerable.Range(1, (DateTime.Now - DateTime.Now.AddDays(-30)).Days)
select new { day = DateTime.Now.AddDays(-30).AddDays(idx).Date});

var orders = (from od in Orders
group od by EntityFunctions.AddSeconds((DateTime?)new DateTime(1970,1,1,0,0,0,0), (int?)od.Created) into g
select new { 
    day = g.Key ,
    web = g.Where( q => q.Source == "web").Count(),
    ios = g.Where( q => q.Source == "ios").Count(),
    android = g.Where( q => q.Source == "android").Count(),
    total = g.Count()
}).OrderByDescending(q => q.day).Take(31);

var days= 
(from d in last_days
join od in orders on d.day equals od.day into x
from od in x.DefaultIfEmpty()
select x );

days.Dump();

这是我得到的结果

enter image description here

现在,我想将最终输出格式化为IEnumerable 5列(day,web,ios,android,total),无论它是否为空。所以我没有空O标志,而是获得日期,而web = ios = android = total = 0.我怎么能这样做? 因此,在没有任何下载的日子里,我仍然可以获得日期和平台为0的条目。

3 个答案:

答案 0 :(得分:2)

这不是最优雅的解决方案,但这样的事情应该有效:

var days = last_days.Select(d =>
  orders.DefaultIfEmpty(new {
    day = d,
    web = 0,
    ios = 0,
    android = 0,
    total = 0
  }).FirstOrDefault(od =>
    od.day == d.Date));

基本的想法是告诉发电机在每种情况下,如果找不到合适的订单条目,应该依靠什么。


回想起来,从空白的石板开始可能更容易。更像是什么:

var last_30_days =
  from idx in Enumerable.Range(1, 30)
  orderby idx descending
  select DateTime.Now.AddDays(idx - 30).Date;

var orders =
  from date in last_30_days
  let datesOrders = Orders.Where(order => order.Created == date)
  select new Info()
  {
    Date = date,
    Web = datesOrders.Where(q => q.Source == "web").Count(),
    iOS = datesOrders.Where(q => q.Source == "ios").Count(),
    Android = datesOrders.Where(q => q.Source == "android").Count(),
    Total = datesOrders.Count()
  };

答案 1 :(得分:0)

如何选择新的DaySum {ord =(ord == null?0:ord.Count)};

而不仅仅是

选择x

答案 2 :(得分:0)

说得对,生成的sql在复杂性方面没问题,在linq上有点生疏我猜

var last_days = (from idx in Enumerable.Range(1, (DateTime.Now - DateTime.Now.AddDays(-31)).Days)
select new { day = DateTime.Now.AddDays(-31).AddDays(idx).Date});

var orders = (from od in Orders
where od.ServiceProviderID == 2
group od by new DateTime(1970,1,1,0,0,0,0).AddSeconds(od.Created).Date into g
select new { 
    day = (DateTime)g.Key ,
    web = g.Where( q => q.Source == "web").Count(),
    ios = g.Where( q => q.Source == "ios").Count(),
    android = g.Where( q => q.Source == "android").Count(),
    total = g.Count()
}).OrderByDescending(q => q.day).Take(32);

var days = (from d in last_days
join od in orders on d.day.Date equals od.day.Date into x
from od in x.DefaultIfEmpty()
select new { 
    day = d.day ,
    web = (od == null) ? 0: od.web,
    ios = (od == null) ? 0: od.ios,
    android = (od == null) ? 0: od.android,
    total = (od == null) ? 0 : od.total
    } );

days.Dump();