2009-08-25 28 views
13

這必須是一個簡單的問題。給定一個標準,如何刪除滿足標準的實體?如何使用條件刪除NHibernate對象?

的基本原理:

HQL和NH標準是NHibernate的特定構建體和因此它們是服務器側DAL實現細節。我不希望他們「泄漏」到客戶端。所以,我們的客戶端提供了LINQ表達式來處理服務器。直到現在,select請求和LINQ to NHibernate處理它們的請求都很好。

但是,現在需要實施批量刪除操作。像往常一樣,客戶端提供一個LINQ表達式,服務器將刪除滿足該表達式的實體。 不幸的是,LINQ to NHibernate在這裏沒有任何幫助。它可以做的最多的是將給定的LINQ表達式轉換爲NHibernate標準。

無論如何,這是故事。我想強調客戶端根本不知道NHibernate,我喜歡它保持這種方式。

P.S.

我使用NH 2.1

回答

-3

在你的資料庫/刀/ PersistenceManager的/不管類:

public IEnumerable<T> FindAll(DetachedCriteria criteria) 

     { 

      return criteria.GetExecutableCriteria(Session).List<T>(); 

     } 

然後

public void Delete(DetachedCriteria criteria) 

     { 

      foreach (T entity in FindAll(criteria)) 

      { 

       Delete(entity); 

      } 

     } 

見戴維·布里翁的帖子Data Access with NHibernate

編輯

據我知道,如果你想使用標準,你需要加載的對象,並在它們之間迭代刪除它們。或者使用HQL或將SQL傳遞給會話。

+6

雖然在處理大量對象時我不喜歡這種方法,因爲它需要先從數據庫中獲取所有實體,然後才能刪除它們。 – 2009-08-25 09:02:57

+3

這是真的,你不需要使用HQL來發出'DELETE FROM WHERE'SQL語句嗎? – DanB 2009-08-25 09:05:50

+2

夥計們,你不認真。一定會有更好的辦法! – mark 2009-08-25 09:06:26

7

您可以使用條件選擇元素的ID,將它們加入字符串並使用HQL刪除它們?

喜歡的東西:

public void Delete(ICriteria criteria, string keyName, string tableName) 
{ 
    criteria.setProjection(Projections.Attribute(keyName)); 
    IList<int> itemIds = criteria.List<int>(); 

    string collection = string.Join(",", Array.ConvertAll<int, string>(itemIds, Convert.ToString)); 

    Session.HQL(string.Format("delete from {0} where {1} in ({2})", tableName, keyName, collection); 
} 

此代碼是沒有測試或編譯(尤其是我不知道的HQL部分的),但我認爲你得到了主意:我們不取整個物體歸功於投影,但只有索引。

+1

這是否意味着數據庫的兩次往返?如果是的話,那麼它不夠好,因爲原生SQL只是在一箇中完成。 – mark 2010-06-18 11:04:52

+1

還是比N + 1更好......我不能用一個更好的方式來使用條件:/ – madprog 2010-07-06 10:12:28

3

簡單地說,直到2.1.2你不能。但是,如果您可以將LINQ表達式轉換爲HQL(或ICriteria轉換爲HQL),那麼您可以使用超載的ISession.Delete()方法,該方法使用傳遞的HQL字符串。

+0

我知道我可以,但是看起來奇怪的是LINQ to NHibernate將LINQ轉換爲Criteria而不是HQL,儘管後者是假設的更強大?可能這畢竟不是那麼簡單。我很想看到一個工作原型... – mark 2010-06-18 18:22:41

+0

我不會說HQL比Criteria更強大,反之亦然。它們只是兩種不同的結構,通常具有不同的用途:HQL用於一次性特定查詢和構建查詢的標準,避免了所有字符串連接的麻煩,通過DetachedCriteria進行模塊化支持,並且仍然更接近您的映射。該示例構造也很甜,但實際上很少使用。總之,我不使用LINQ for nhibernate -yet-,所以我沒有任何例子可以給。然而,直到一個新版本支持你想要的,標準只適用於選擇語句 – Jaguar 2010-06-18 21:30:37

-5

我知道這是一個古老的問題,但爲爭辯的緣故;如果使用存儲庫模式,你可以聲明刪除方法,執行以下操作:

public void Delete(System.Linq.Expressions.Expression<System.Func<TEntity, bool>> predicate) 
{ 
    var entities = _session.Query<TEntity>().Where(predicate); 
    foreach (var entity in entities) 
     _session.Delete(entity); 
} 

注意代碼使用表達式,以便倉庫接口足夠通用的,所以你也可以實現例如實體框架庫。

+4

不完全。你所做的是使用表達式來獲取實體,然後逐個刪除它們。這不是通過表達式刪除實體。我的意思是有一個接收表達式的本地API,將它轉換爲相應的刪除SQL語句,然後一次刪除所有實體。 – mark 2011-08-20 05:19:09

+2

這需要一個很大的警告,說明當你有很多對象時它不會很好。 – 2013-04-18 18:08:02