2010-09-22 146 views
1

我建立了一個NHibernate的存儲庫層,其中我有以下find方法:添加條件LINQ查詢

public IList<TEntity> Find(Expression<Func<TEntity, bool>> query) 

我想一個條件添加到該方法中的查詢。額外的條件應該將行限制在RemovedAt大於DateTime.Now的地方。

說明使用SQL:

讓我們假設我有以下SQL查詢:

SELECT * FROM users WHERE first_name LIKE 'a%' OR last_name LIKE 'a%' 

它看起來像這樣修改後:

SELECT * FROM users WHERE (first_name LIKE 'a%' OR last_name LIKE 'a%') AND created_at > '2010-09-22 19:31' 

它可以用做linq查詢,還是在nhibernate?

編輯

對不起,忘了提,所有的實體沒有RemovedAt方法。接口被聲明爲:

public interface IRepository<TEntity, TKey> where TEntity : class, new() 

我通過查找與該名稱的屬性和使用反射來更新的值更改CreatedAt/RemovedAt/UpdatedAt(在各自的方法)。

回答

2

首先,我不知道爲什麼你就是不返回的IQueryable並讓該方法的用戶確定他們是否想把它當作一個列表,等等。因爲IQueryables不執行,直到實際需要,你可以不斷加入到表達式樹,直到你真的需要它。

在這種情況下,當您將其更改爲對象列表時,即當查詢將轉換爲列表時,實際上將針對數據庫執行查詢。

如果你真的想保持接口作爲IList的,而不是一個IQueryable,只是你編譯前添加一個額外的表達式表達式樹。

因爲我對根級表達式樹的工作有限,所以我可能會給你錯誤的語法,所以這裏是一個不同類型的例子,可能會給你足夠的信息來說明我在說什麼:

var query = something.Where(n => n.FirstName.StartsWith("N")) ; 
query = query.Where(n => n.created_at > DateTime.Now); 
return query.ToList(); 

我希望是有道理的。您可以繼續向表達式樹添加條件,直到它被編譯並執行。

我仍然建議通過IQueryable的角落找尋不過,來代替。在我的示例中,您只需返回查詢,而不是先調用ToList。它使得流利的語法更容易,並且在nHibernate中執行會更好,因爲nHibernate會在調用數據庫之前考慮所有條件。例如,如果您只需要一個累加器或一個計數,那麼將在數據庫中進行處理,而不是將所有行都拉回到列表中,然後遍歷它以獲取聚合或計數。

+0

公開IQueryable還會暴露我想在存儲庫類中處理的較低級別異常。無論如何,我會讓服務層處理RemovedAt過濾器。 – jgauffin 2010-09-23 05:23:22

+0

對於一些額外的抽象;請看http://code.google.com/p/linq-specifications/,這可以爲您提供更清晰/更統一的方法來制定查詢。 – DanP 2010-09-23 11:58:42

0

有關他們的資料庫的頂部使用Business Logic Layer與像AutoMapper一個工具將數據傳輸對象和實體模型之間的映射,使用Predicate BuilderLinqKit以允許沿着那些你的MVC/API控制器添加額外System.Linq.Expressions.Expression過濾器默認過濾器您設置了您的業務組件。

使用謂詞構建器將允許您在將其發送到AutoMapper進行展平之前動態修改您的IQueryable,即將列表帶入內存。