2012-07-25 72 views
0

我希望能夠將我的所有數據按月分組,即使有些月份不包含任何數據。此時,我可以分組,但返回的數據只包含數據。Linq to Entity,選擇無價值團體

下面是我的代碼如下所示:

var twelveMonthAgo = date.AddMonths(-12).Date; 
var twelveMonthAgoFirstOfMonth = new DateTime(twelveMonthAgo.Year, twelveMonthAgo.Month, 1, 0, 0, 0, 0); 

var data = (from i in Database.Users 
      where i.RegisterDate >= twelveMonthAgoFirstOfMonth 
      group i by new {y=i.RegisterDate.Year,m = i.RegisterDate.Month} into g 
      select new UserStatistic{ Date = EntityFunctions.CreateDateTime(g.Key.y, g.Key.m, 1, 0, 0, 0) 
             , UserCount = g.Count(o => o.Id) 
            }); 

//The code below is what I would like to remove           
var toReturn = new List<UserStatistic>(); 
var allData = data.ToList(); 
DateTime datei = twelveMonthAgoFirstOfMonth; 
while (datei.Year<= date.Year && datei.Month<=date.Month){ 
    var info = allData.SingleOrDefault(x => x.Date.HasValue && x.Date.Value.Year == datei.Year && x.Date.Value.Month == datei.Month); 
    toReturn.Add(info ?? new UserStatistic { Date = datei, UserCount = 0, PaymentPaid = 0 }); 
    datei = datei.AddMonths(1); 
} 
return toReturn.AsQueryable(); 

正如你可以看到,註釋下的代碼建立過去12個月的收集和檢查,如果一些數據已經從數據庫中,並填寫如果存在的話收集集合,否則將其設爲0.

我該怎麼做,而不必在評論下面做代碼?

+0

是「數據」中的第一個月還是1月('1')還是第一年?同樣,上個月應該是去年的12月份('12'),還是上個月的'data'? – Jodrell 2012-07-25 15:55:50

+1

您需要將日期的左外連接執行到聚合值。一個group將總會忽略不分組的值。 – casperOne 2012-07-25 16:00:16

+0

@Jodrell日期範圍並不重要,這可能會改變。我想要的是獲得最後x個月的數據。 – 2012-07-25 16:04:26

回答

1

這是一個使用一組一些代碼加入到一個子查詢得到你想要的結果:

DateTime date = DateTime.Today; 
DateTime firstOfMonth = new DateTime(date.Year, date.Month, 1); 
DateTime twelveMonthAgoFirstOfMonth = firstOfMonth.AddMonths(-12); 

// Generate a collection of the months and years for the last 12 months 
var monthYears = Enumerable.Range(-12, 12).Select(monthOffset => { DateTime monthDate = firstOfMonth.AddMonths(monthOffset); return new { y = monthDate.Year, m = monthDate.Month }; }); 

// Go through the list of months and years and join them to the users retrieved from the database in the subquery. 
var data = from monthYear in monthYears 
      join i in (from i in Database.Users 
         where i.RegisterDate >= twelveMonthAgoFirstOfMonth && i.RegisterDate < firstOfMonth 
         select i) on monthYear equals new { y = i.RegisterDate.Year, m = i.RegisterDate.Month } into gj 
      select new UserStatistic() { Date = new DateTime(monthYear.y, monthYear.m, 1), UserCount = gj.Count() }); 

這也可以表示爲一個左外子查詢組加入:

DateTime date = DateTime.Today; 
    DateTime firstOfMonth = new DateTime(date.Year, date.Month, 1); 
    DateTime twelveMonthAgoFirstOfMonth = firstOfMonth.AddMonths(-12); 
    var monthYears = Enumerable.Range(-12, 12).Select(monthOffset => { DateTime monthDate = firstOfMonth.AddMonths(monthOffset); return new { y = monthDate.Year, m = monthDate.Month }; }); 

    var data = (from monthYear in monthYears 
       join i in (from i in Database.Users 
          where i.RegisterDate >= twelveMonthAgoFirstOfMonth && i.RegisterDate < firstOfMonth 
          group i by new {y = i.RegisterDate.Year, m = i.RegisterDate.Month} into g 
          select new { Key = g.Key, UserCount = g.Count() }) on monthYear equals i.Key into j 
       from k in j.DefaultIfEmpty() 
       select new UserStatistic() { Date = new DateTime(monthYear.y, monthYear.m, 1), UserCount = k != null ? k.UserCount : 0 }); 

由於我沒有EF模型,您必須嘗試一下,看看您是否需要用EntityFunctions.CreateDateTime替換new DateTime

+0

你的第二個例子正是我進入它的!它運作良好。非常感謝您的意見。 – 2012-07-25 18:49:09

1

我還沒有編譯和調試,但它應該給我一個想法,我認爲你可以解決你的問題。我使用Enumerable.Range爲您需要的月份生成一組佔位符。然後我必須選擇左邊加入placeHoldersdata併合並,或者只是將這些遺漏連接起來。

我也重新格式化了這個問題的代碼,以幫助我理解它。

IQueryable<UserStatistic> GetPastMonths(int months) 
{  
    var limitDay = date.AddMonths(-months).Date; 
    var limit = new DateTime(limitDay.Year, limitDay.Month, 1, 0, 0, 0, 0); 

    var placeHolders = Enumerable.Range(0, months + 1) 
     .Select(m => 
      new UserStatistic 
       { 
        Date = limit.AddMonths(-m), 
        UserCount = 0 
       }); 

    var data = Database.Users 
     .Where(i => i.RegisterDate >= limit) 
     .GroupBy(i => new {y=i.RegisterDate.Year, m = i.RegisterDate.Month}) 
     .Select(g => 
      new UserStatistic 
       { 
        Date = EntityFunctions.CreateDateTime(
          g.Key.y, 
          g.Key.m, 
          1, 
          0, 
          0, 
          0), 
        UserCount = g.Count(o => o.Id) 
       }); 

    return data.Concat(placeHolders 
     .Where(p => !data.Any(d => d.Date == p.Date))) 
     .AsQueryable(); 
} 

的cocatenating的ommissions方法幾乎garaunteed給數據傳回在一個不合邏輯的訂單,但,你有沒有garauntees反正除非你子句中使用的命令。

+0

這看起來接近我現在正在試驗的東西。讓我完成我的例子,我更仔細地看待你的例子。謝謝 – 2012-07-25 17:19:21