2011-09-28 103 views
0

我有一個LINQ查詢的問題,不知道如何解決它:/group by join and aggregate(linq)

我有兩個表。一個是屬性,第二個是來自屬性的行,但我需要從行中總結小時並將其分配給屬性;無法解釋得非常好;)這是我的查詢,我試圖創建:

var query = (from ta in session.db.TimesheetAttributes 
      join tr in session.db.TimesheetRows on ta.Id equals tr.TimesheetAttributesId into tempTR 
      from ttr in tempTR.DefaultIfEmpty() 
      group ttr by new { ta.TimesheetId, ta.Date, ta.SickNote, ta.Vacation, ta.OccasionVacation } into g 
      select new 
      { 
       Id = g.Key.TimesheetId, 
       Date = g.Key.Date, 
       WeekDay = g.Key.Date.ToString("dddd", new CultureInfo("pl-PL")), 
       Description = String.Format("{0:dd/MM/yyyy}", g.Key.Date), 
       SickNote = g.Key.SickNote, 
       Vacation = g.Key.Vacation, 
       OccasionVacation = g.Key.OccasionVacation, 
       Hours = String.Format("{0:HH:mm}", (new DateTime(g.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks))) 
      }).OrderBy(c=>c.Date).ToList(); 

的問題是,不是每個屬性的有行,這就是爲什麼我試圖使用DefaultIfEmpty(),但這個查詢不工作:(

我的舊的查詢工作,但我的ORM,使每一行一個新的查詢,所以如果我有1000個TimesheetAttributes它使1000種選擇:/

這裏是我的舊的查詢:

var query = (from c in session.db.TimesheetAttributes 
      where ((c.Active == true) 
        && (c.Timesheet.Active == true) 
        && (c.ValidFrom <= validDate) 
        && (c.ValidTo > validDate) 
        && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId)) 
      select new 
      { 
       Id = c.TimesheetId, 
       c.Date, 
       WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")), 
       Description = String.Format("{0:dd/MM/yyyy}", c.Date), 
       Hours = String.Format("{0:HH:mm}", (new DateTime((c.TimesheetRows.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))), 
       c.SickNote, 
       c.Vacation, 
       c.OccasionVacation 
       }).OrderBy(c => c.Date).ToList(); 

編輯:

這是我得到的異常:「異常已通過調用的目標引發異常」 的InnerException:「對象引用不設置到對象的實例」

+1

你能告訴我具體什麼不起作用嗎?你得到的錯誤/例外,或者你總是得到空的結果... – Frederiek

+0

我沒有從這個問題得到任何東西可以PLZ顯示查詢的一些結果 –

+0

ive編輯我的帖子 – Cfaniak

回答

0

的問題,你與你有關的舊查詢通常被稱爲n+1 problem

你應該能夠如下,以適應您的原始查詢:

var query = (from c in session.db.TimesheetAttributes 
      from cr in c.TimesheetRows 
      where ((c.Active == true) 
        && (c.Timesheet.Active == true) 
        && (c.ValidFrom <= validDate) 
        && (c.ValidTo > validDate) 
        && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId)) 
      select new 
      { 
       Id = c.TimesheetId, 
       c.Date, 
       WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")), 
       Description = String.Format("{0:dd/MM/yyyy}", c.Date), 
       Hours = String.Format("{0:HH:mm}", (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))), 
       c.SickNote, 
       c.Vacation, 
       c.OccasionVacation 
       }).OrderBy(c => c.Date).ToList(); 

如果仍然whinges,你可以嘗試添加一個tenary運營商hours屬性...

Hours = String.Format("{0:HH:mm}", !(cr == null) && cr.Any() ? (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks))) : DateTime.MinValue 

編輯:

我明白你的意思了,我的大腦還沒有醒來。您遇到的問題是底層查詢提供程序沒有注意到它需要獲取TimesheetAttributes以及關聯/相關的TimesheetRows。這可能是因爲TimesheetRows深深地埋藏在生成您選擇的匿名類型的表達式中。

我的查詢語法不豔(我喜歡做的Lambda - 我覺得它更面向未來但是這只是一種感覺),但我給它一個鏡頭...

var query = (from res in 
       (from c in session.db.TimesheetAttributes   
       where ((c.Active == true)   
         && (c.Timesheet.Active == true)   
         && (c.ValidFrom <= validDate)   
         && (c.ValidTo > validDate)   
         && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId))   
       select new   
       { 
        c = c, 
        cr = c.TimesheetRows 
       }) 
      select new 
      { 
       Id = c.TimesheetId,   
       c.Date,   
       WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")),   
       Description = String.Format("{0:dd/MM/yyyy}", c.Date),   
       Hours = String.Format("{0:HH:mm}", (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))),   
       c.SickNote,   
       c.Vacation,   
       c.OccasionVacation   
       }).OrderBy(c => c.Date).ToList(); 

它看起來比原來更醜陋,我確信有更好的方法來做這件事,但它應該使表達式足夠清晰,以便您的查詢提供程序(L2S或其他)意識到它需要返回兩個實體,並且避免n + 1問題。

+0

不工作錯誤「cr in c.TimesheetRows」我試着用「從c.TimesheetRows中的cr」,但比使用作爲類不集合,也嘗試與「let cr = c.TimesheetRows」buth比得到null對象引用 – Cfaniak

+0

@Cfaniak:對不起,我錯過了'從'但是你說你嘗試過嗎? 「用作課堂而不是集合」是什麼意思? 'Hours'應該是'IEnumerable '還是'string'? – Smudge202

+0

我的意思是當我從cr使用比我不能使用cr.Aggregate,因爲它使用它像類後cr。我收集了所有字段而不是集合 – Cfaniak