2009-06-16 60 views
2

我知道避免Hibernate/NHibernate中N + 1選擇問題的基本方法,但遇到了一個問題的變體,我無法找到一個好的解決方案。避免N + 1選擇在NHibernate中使用業務規則

我有以下三個實體映射:項目,類別和客戶。一個項目與多個類別關聯到一個類別,並且一個類別被多對一地映射到客戶。迄今爲止,沒有什麼特別的

我的應用程序中的標準查詢是獲取給定客戶的所有項目。我該使用下列標準,試圖獲取項目熱切的類別,以避免N + 1個選擇檢查項目時,分類屬性來完成:

ICriteria criteria = mySession.CreateCriteria(typeof(Item)); 
    .CreateCriteria("Categories", NHibernate.SqlCommand.JoinType.InnerJoin) 
     .Add(Expression.Eq("Customer", c)); 
criteria.SetFetchMode("Categories", FetchMode.Eager); 

return criteria.List(); 

但是,這並不工作,NHibernate的仍然獲取了稍後每項選擇一個類別。

我相信會發生的事情是,NHibernate知道第一個查詢的結果被過濾(在Customer上),並且查詢返回的類別可能不完整,因此它稍後必須執行單獨的查詢獲取類別。 (這個假設是否正確?我認爲NHibernate必須以這種方式來確保正確的結果。)

但是,根據我的業務規則(或者你想要稱之爲什麼),一個項目不能屬於來自多個客戶的類別,所以實際上我知道第一個查詢的結果實際上是完整的。

我的問題是:我可以告訴NHibernate有關此業務規則的任何方式嗎?有沒有另外一種方法可以避免N + 1在這種情況下的選擇(這看起來很常見)?

回答

2

會嘗試回答我自己的問題,因爲到目前爲止我還沒有得到任何答案。

我的解決辦法是在兩個查詢來劃分的問題:第一個獲得屬於客戶的有關物品的ID:

IQuery query = mySession.CreateQuery("select item.Id from Item as item " 
    + "join item.Categories as category " 
    + "join category.Customer customer " 
    + "where customer.id=:id") 
    .SetInt32("id", c.Id); 
IList itemIds = query.List(); 

我再提取實際的項目,而不涉及對客戶的任何限制,只使用這些ID。這樣NHibernate的知道它可以從一個單一的加盟讓所有類別,避免了問題中提到的N + 1種選擇:

ICriteria criteria = mySession.CreateCriteria(typeof(MapItem)) 
    .SetFetchMode("Categories", FetchMode.Eager) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()) 
    .Add(Expression.In("Id", itemIds)); 
IList items = criteria.List(); 

我不能拿出任何解決方案,減少這一個工作,單查詢。另外,這種方法迫使程序員對NHibernate的內部工作知道得太多,當你編寫新的查詢或標準時,很容易錯過。更通用的解決方案將是更可取的。