2012-01-20 41 views
2

我使用NHibernate的3.2和我有,看起來像一個倉庫方法:NHibernate的簡化版,IQueryable的似乎延遲執行

public IEnumerable<MyModel> GetActiveMyModel() 
    { 
     return from m in Session.Query<MyModel>() 
       where m.Active == true 
       select m; 
    } 

預期其中一期工程。但是,有時,當我用這個方法我想進一步將其過濾:

var models = MyRepository.GetActiveMyModel(); 
    var filtered = from m in models 
        where m.ID < 100 
        select new { m.Name }; 

將會產生相同的SQL作爲第一個和第二個過濾器,並選擇必須事後進行。我認爲LINQ的重點在於它形成了一個表達式樹,在需要時可以將其解開,因此可以創建正確的SQL作業,從而節省我的數據庫請求。

如果不是這樣,這意味着我所有的存儲庫方法都必須返回完全所需的內容,而且我無法使用LINQ進行更深入的處理而不會受到懲罰。

我有這個錯誤嗎?

更新

響應於下面的評論:我省略其中I遍歷結果行,這會導致初始SQL要運行(active = 1的)和第二濾波器(ID < 100)顯然是在.NET中完成的。

而且,如果我和

var models = MyRepository.GetActiveMyModel(); 
var filtered = from m in models 
       where m.Items.Count > 0 
       select new { m.Name }; 

替換代碼的第二塊它生成初始SQL檢索活動記錄,然後運行爲每個記錄單獨的SQL語句來找出有多少項目有,而不是寫類似的東西,我期望:

SELECT Name 
FROM MyModel m 
WHERE Active = 1 
    AND (SELECT COUNT(*) FROM Items WHERE MyModelID = m.ID) > 0 

安東尼

+0

我不知道你的意思,NHibernates IQueryables肯定懶洋洋地評估。你能舉出一個例子,當你得到兩個數據庫查詢並期待一個?這兩個例子都創建了Queryable,不應該產生任何數據庫請求。 –

回答

7

您是從方法,返回IEnumerable<MyModel>這將會導致內存評估,即使底層序列是IQueryable<MyModel>

如果要允許GetActiveMyModel之後的代碼添加到SQL查詢中,請改爲返回IQueryable<MyModel>

+0

謝謝。不敢相信我一直這麼愚蠢! – littlecharva

+3

@littlecharva:有時它只需要第二組眼睛。 –

1

您正在運行IEnumerable的擴展方法「Where」而不是IQueryable's。它仍然會懶惰地評估並給出相同的輸出,但是它會在輸入時評估IQueryable,並且您正在過濾集合而不是數據庫。

當您稍後在另一個表(計數)上添加額外的條件時,它必須從數據庫中懶惰地獲取每一個Items集合,因爲它在知道條件之前已經評估了IQueryable。

(是的,我也想是對的IEnumerable廣泛的擴展方法,而不是是虛擬的成員,但是,唉,他們不是)