2012-02-27 47 views
0

一個真正的查詢在LINQ到實體對像這樣的數據庫工作得很好。在試圖單元測試查詢使用LINQ到對象我得到一個空引用異常。如何處理Linq中的一系列左連接到對象?

我已經轉載它在linqPad。

void Main() 
{ 
    var _news= new [] {new {ID=0, ExpiryDate=(DateTime?)null }, new {ID=1,ExpiryDate=(DateTime?)DateTime.UtcNow.AddDays(-1)}}; 
    var _newsRegionSource = new RegionSource[]{}; 
    var _entitledRegions=new Region[] {}; 

    var validNews = from n in _news.Where(n=>n.ExpiryDate==null || n.ExpiryDate>DateTime.UtcNow) 
     select n; 
    var q = from n in validNews 

      join r in _newsRegionSource 
      on n.ID equals r.ID into rLeft 
      from rn in rLeft.DefaultIfEmpty() 

      join erL in _entitledRegions 
      // adding .DefaultIfEmpty() here instead moves the exception to erL.ID 
      //NullReferenceException underlining rn at rn.RegionID 
      on rn.RegionID equals erL.ID into erLeft 
      from er in erLeft.DefaultIfEmpty() 

      where rn==null | (rn.ID==n.ID && er!=null) 
      select new {News=n,RegionID=(rn==null? (byte?)null: rn.RegionID)}; 
      var materialized=q.ToArray(); 
     materialized.Dump(); 

} 

public class Region 
{ 
    public byte ID {get;set;} 
} 
public class RegionSource 
{ 
    public int ID{get;set;} 
    public byte RegionID{get;set;} 
} 

我也試過

  • 確保有在所有的源陣列中的至少1項(但他們仍然會導致0行對於這類查詢/箱),
  • 包裝的陣列,.AsQueryable()

如何處理左加入的可能0排在Linq to Objects

回答

0

實體行爲有點不同於LINQ到有關左外連接的對象,正如你在這裏發現的那樣。你仍然可以通過非常輕微的調整來實現它。訣竅是提供一個連接表達式,避免引用null

我第一次嘗試,我不得不聯接表達式:

 on (rn == null : Int32.MinValue : rn.RegionID) equals erL.ID into erLeft 

不到,因爲Int32.MinValue滿足看起來像它既是一個任意值,也因爲它可能是依賴於RegionID有效值你用法。另一個選擇是使用一個可爲空的int,我發現它更令人滿意,因爲它提供了相同的結果而不劫持Int32.MinValue的情況。

 on (rn == null ? (Int32?) null : rn.RegionID) equals erL.ID into erLeft 

現在改變OR(|)在接下來的條件短路(||)如下:

 where rn==null || (rn.ID==n.ID && er!=null) 

代替NullReferenceException你應該得到一個消息,RegionID結果現在,如預期。