2010-05-07 82 views
0

我很難確定處理此問題的最佳方法...使用實體框架(和L2S),LINQ查詢返回IQueryable。我已閱讀關於DAL/BLL是否應返回IQueryable,IEnumerable或IList的各種意見。假設我們使用IList,那麼查詢立即運行,並且該控件不會傳遞到下一層。這使得單元測試更容易,等等。你失去了在更高級別上優化查詢的能力,但是你可以簡單地創建另一個方法,允許你改進查詢並仍然返回IList。還有更多的優點/缺點。到現在爲止還挺好。IQueryable和延遲加載

現在來實體框架和延遲加載。我在.NET 4/VS 2010使用POCO對象與代理人在表示層我做的:

foreach (Order order in bll.GetOrders()) 
{ 
    foreach (OrderLine orderLine in order.OrderLines) 
    { 
    // Do something 
    } 
} 

在這種情況下,GetOrders()返回的IList所以它返回到PL之前立即執行。但在接下來的foreach中,你有懶惰的加載,它執行多個SQL查詢,因爲它獲取所有OrderLines。所以基本上,PL在錯誤的層中「按需」運行SQL查詢。

有沒有什麼明智的方法可以避免這種情況?我可以關閉懶惰的加載,但那麼每個人都抱怨EF1沒有這個「特徵」有什麼意義?我承認它在很多情況下非常有用。所以我看到幾個選項:

  1. 以某種方式刪除實體中的所有關聯並添加方法以返回它們。這違背了默認的EF行爲/代碼生成,並且使得難以執行一些組合(多個實體)LINQ查詢。這似乎是一個倒退。我投不到。
  2. 如果我們有延遲加載,這使得它很難單元測試,然後一路走,並返回IQueryable。你會有更多的控制層次。我仍然認爲這不是一個好的選擇,因爲IQueryable將您與L2S,L2E或您自己的IQueryable的完整實現聯繫在一起。延遲加載可以「按需」運行查詢,但不會將您與任何特定的界面綁定。我投不到。
  3. 關閉延遲加載。您必須手動處理您的關聯。這可以通過加載的.Include()來進行。我在某些特定情況下投贊成票。
  4. 保持IList和延遲加載。我在很多情況下投贊成票,只是由於其他人的麻煩。

還有其他的選擇或建議嗎?我還沒有找到真正讓我信服的選項。

回答

0

您可以讓您的方法接受某種加載策略。

Func<ObjectSet<Order>, ObjectQuery<Order>> loadSpan = 
orders=> orders.Include("OrderLines"); 

foreach (Order order in bll.GetOrders(loadSpan)) 
{ 
    foreach (OrderLine orderLine in order.OrderLines) 
    { 
    // Do something 
    } 
} 

而且你GetOrders方法裏面,你這樣做

public IList<Oorder> GetOrders(
        Func<ObjectSet<Order>, ObjectQuery<Order>> loadSpan) 
{ 
    var ordersWithSpan = loadSpan(context.OrderSet); 
    var orders = from order in ordersWithSpan 
       where ...your normal filters etc 

    return orders.ToList(); 
} 

這將允許你指定每個用例全部負荷曲線圖。 可以ofcourse也包裹這些戰略起來的一些包裝類,所以你可以這樣寫:

//wrapped in a static class "OrderLoadSpans" 
foreach (Order order in bll.GetOrders(OrderLoadSpans.WithOrderLines)) 

HTH

+0

你沒有涵蓋「從UI層延遲加載/ SQL執行」,但仍幫助。我認爲最後一段代碼與我所尋找的最接近。看起來你有1)易用性,2)封裝/ SoC /單元可測試/等等,3)使用高級功能(急切加載等)的能力。選擇兩個。你不能擁有全部三個。無論如何,感謝您的幫助。 – 2010-05-10 12:09:46