2012-01-05 40 views
1

我在我的網頁有幾個下拉菜單。這些鏈接並具有類似的雙向鏈接類結構。nhibernate3查詢 - 收藏與收藏

換句話說:類Alpha有一個類Beta的列表,而類又有一個類Charlie的列表。每個Beta類也有它自己的Alpha列表(它所屬的列表),每個類Charlie都有它自己的Beta列表。

我使用的NHibernate 3與流利的nhibernate和automappings。

現在。如果我只是運行一個

session.CreateCriteria<Alpha>().SetMaxResults(1000).List<Alpha>(); 

我收到N + 1的問題,當我循環的集合。

我看到它的方式如下SQL的應該是所有與查詢到數據庫

select top 1000 * from Alpha 
select top 1000 * from Beta 
select top 1000 * from Charlie 
select * from Alpha2Beta 
select * from Beta2Charlie 

但是我怎麼寫這個工作查詢?

+0

您在Alpha和Beta,Beta和Charlie之間有雙向關係 - 您如何期望只查詢這三個表?必須有鏈接表來實現這個... – 2012-01-05 10:37:43

+0

哦,我很傻,你絕對是對的!我將更新文本 – Ivar 2012-01-05 11:17:48

+0

聽起來像您正在使用無狀態會話。 StatelessSession沒有緩存 - 並且無狀態會話中的對象不能延遲加載。這意味着您將無法預取組件並執行組合查詢。如果是這種情況 - 您需要在查詢中使用.Fetch()以便從Alpha2Beta和Beta2Charlie中加載子對象。你仍然會有一些重複 - 但並不像N + 1那麼糟糕。 – Origin 2012-01-05 15:54:02

回答

0

如果您使用的是Criteria,則需要包含方法調用Dyanmic Fetching

+0

據我所知,你不能在多個集合上使用動態抓取。您可以通過這種方式獲取多個相關實體和一個集合。 – 2012-01-05 19:14:46

1

Ayende在他的博客中展示了一個不錯的竅門。我沒有親自嘗試過,因爲我決定改變我的BL以避免這個問題,所以請帶上一點鹽。

你應該可以單獨加載集合,讓NHibernate使用NHibernate Futures來連接實體。因爲它不是一個輕的主題,所以你最好是read his blog post

+0

這是一種時尚,但即使你查詢每個Alpha和每個Beta,你仍然會遇到SELECT N + 1,因爲NH必須查詢Alpha <-> Beta關聯。 – Rytmis 2012-01-05 22:57:50

+0

再一次,我沒有試過它只是指向資源,但爲什麼你需要另一個N + 1,如果你加載Alpha和Beta AND連接表?我並不是說只是加載所有東西都可以,但如果不是這樣,那是因爲它不被支持,並不是因爲它不能實現。當然,這需要一些創造性的映射:)(映射連接表) – 2012-01-05 23:22:33

+0

如果您查詢Alpha和Betas,身份映射(L1緩存)將確保您在訪問關聯時不需要加載任何Betas阿爾法。但是,在查詢中沒有加載的是關聯表的內容,所以當你點擊關聯時會發生什麼是「SELECT FROM Alpha_to_Beta WHERE Alpha_Id = n」,而不是「SELECT FROM Alpha_to_Beta INNER JOIN Beta ...」 - 也就是說,如果關聯尚未加載,則無法預先加載實體本身。這是否澄清了我的觀點? :-) – Rytmis 2012-01-06 15:40:48

0

據我所知,按照查詢級別進行查詢是沒有辦法的,就像使用連接抓取一樣。但是,如果你改變了映射並設置默認獲取模式協會是「子查詢」,你可能會驚喜:

Hibernate Documentation(同樣適用與NHibernate):

對於集合上的fetch =「subselect」,您可以告訴Hibernate不僅在第二個SELECT(懶惰或非懶惰)中加載此集合,還會爲所有在您加載的「擁有」實體中加載其他集合 第一個SELECT。這是 獲取多個並行集合」

這意味着所要求的第一個關聯時,NHibernate的會,而不是裝載一個聯想,回憶你用得到的根實體的查詢特別有用,然後加載查詢返回的根實體類型的所有實例的關聯數據。

也就是說,如果您正在加載1K個實體並且您希望每個關聯的記錄數超過一對,那麼您'可能只是從(SELECT N + 1)^ 2轉到「我只是將整個數據庫加載到內存中的聖誕垃圾」.-)

(請注意,如果你這樣做,並且有一個場景可以加載Alpha列表,但只需要關聯一個Alpha的Betas,你仍然會加載所有這些,並且你無能爲力。但實際上,我發現這是一種非常罕見的情況,所以通常對子查詢進行適當的調整。)