2012-07-12 79 views
0

我有一個包含開始/結束日期的對象列表。如果當前記錄存在,我試圖找到當前記錄,或者如果失敗了,最近過期的記錄。LINQ查詢與聚合在哪裏條款

  • 目前被定義爲在過去,無論是空的最後一天(開放式)或日期和結束日期在未來的一個非空的開始日期。
  • 最近過期可能被定義爲沒有最近結束日期的當前時間段。從理論上講,每個對象表示的時間跨度不應該重疊,所以我認爲最近的結束日期對於最近的過期已經足夠了。

我試圖按照this answer到類似的問題,但我似乎無法找到正確的條目時有列表是未來名花有主項(即有開始/結束日期,其中兩者都在未來)。

我的嘗試如下,其中a是開始日期,b是結束日期,c是調試時使用的指示符,d用於定義列表項類型。我只對感興趣的類型2.

[TestMethod] 
    public void TestRetrievalOfListElements() 
    { 

     var baseDate = DateTime.Now; 

     var list = new[] 
     { 
      new { a = new DateTime?(baseDate.AddDays(-90)), 
        b = new DateTime?(baseDate.AddDays(-60)), c = "LongExpired", d=1 }, 
      new { a = new DateTime?(baseDate.AddDays(-190)), 
        b = new DateTime?(baseDate.AddDays(-160)), c = "LongestExpired", d=1 }, 
      new { a = new DateTime?(baseDate.AddDays(-59)), 
        b = new DateTime?(baseDate.AddDays(+20)), c = "Current", d=1 }, 
      new { a = new DateTime?(baseDate.AddDays(-159)), 
        b = new DateTime?(baseDate.AddDays(-91)), c = "LongerExpired", d=1 }, 
      new { a = new DateTime?(baseDate.AddDays(-90)), 
        b = new DateTime?(baseDate.AddDays(-60)), c = "LongExpired", d=2 }, 
      new { a = new DateTime?(baseDate.AddDays(-190)), 
        b = new DateTime?(baseDate.AddDays(-160)), c = "LongestExpired", d=2 }, 
      new { a = new DateTime?(baseDate.AddDays(-59)), 
        b = new DateTime?(baseDate.AddDays(+20)), c = "Current", d=2 }, 
      new { a = new DateTime?(baseDate.AddDays(-159)), 
        b = new DateTime?(baseDate.AddDays(-91)), c = "LongerExpired", d=2 }, 
      new { a = new DateTime?(baseDate.AddDays(+21)), 
        b = new DateTime?(baseDate.AddDays(+60)), c = "Future", d=2 }, 

     }.ToList(); 

     // The following isn't really right either as it doesn't take into account 
     // whether d is of type 1 or 2 either. Not sure how to combine aggregates and 
     // other conditions ie MIN and of type 2 

     var oldestEntry = (from x in list 
          where x.a == list.Min(d => d.a) && 
          x.d == 2 
          select x).FirstOrDefault(); 

     Assert.IsTrue(oldestEntry.a == baseDate.AddDays(-190), "Expected oldest date to be 190 days earlier than today"); 

     var latestEntryThatIsntInTheFuture = 
          (from x in list 
          from y in list.Where(z => z.d == 2 && z.a <= baseDate) 
          where x.a == list.Max(d => d.a) && 
          x.d == 2 
          select x).FirstOrDefault(); 

     Assert.IsTrue(latestEntryThatIsntInTheFuture.a == baseDate.AddDays(-59), "Expected latest date that isn't in the future to be 59 days earlier than today"); 



    } 

回答

1

這可能是你在找什麼:

// Find the current which is defined as a non null start date that is in the past 
// and either a null end date (open ended) or and end date in the future. 
var now = DateTime.Now; 
var current = list 
    .Where(x => x.a.HasValue && x.a.Value < now && (!x.b.HasValue || x.b.Value > now)) 
    .FirstOrDefault(); 
if (current == null) 
{ 
    //Then find most recently expired 
    current = list.Where(x => x.b.HasValue) 
        .OrderByDescending(x => x.b) 
        .FirstOrDefault(); 
} 

所以你並不需要在查詢聚集在我看來。

+0

乍一看,這看起來不錯。我很可能不需要查詢中的聚合。你的想法簡單地應用順序也很整齊。我覺得我有一個讓人看起來很容易看起來相當困難的不可思議的訣竅。我將對您的代碼執行一些測試,並看看我如何繼續。謝謝。 – 2012-07-12 08:04:39

+0

它工作的一種享受。謝謝。 – 2012-07-12 08:13:16