2011-07-07 29 views
1

我有兩個實體,位置和行業,以及它們之間的鏈接表。我在兩個實體之間配置了雙向多對多關係。使用HQL進行多對多關係的次優查詢

在搜索查詢中,我試圖選擇與行業列表關聯的位置。

經過幾天和幾天試圖糾纏標準API,我決定下降到HQL並放棄標準API。但即使這樣對我來說也不太合適 - 看起來,無論我是手寫這個HQL查詢還是讓條件API執行它,我都會得到相同的結果。

我設法生產出在兩個方面正確的結果 - 這樣的:

var q = Data.Query("select distinct loc from Location loc join loc.Industries ind where ind in (:ind)"); 

q.SetParameterList("ind", new Industry[] { Data.GetIndustry(4), Data.GetIndustry(5) }); 

和(更好),這樣的:

var q = Data.Query("select distinct loc from Location loc join loc.Industries ind where ind.id in (:ind)"); 

q.SetParameterList("ind", new int[] { 4, 5 }); 

不幸的是,結果在一個次優查詢:

select distinct 
    location0_.Id as Id16_, 
    location0_.Name as Name16_, 
    (etc.) 
from Location location0_ 
    inner join LocationIndustry industries1_ 
    on location0_.Id=industries1_.LocationId 
    inner join Industry industry2_ 
    on industries1_.IndustryId=industry2_.Id 
where 
    industry2_.Id in (? , ?) 

爲什麼要多加入?

NH不夠聰明,無法知道Industry.Id屬性是唯一涉及查詢的行業屬性,它存儲在LocationIndustry鏈接表中,並且不需要額外加入行業桌子本身?

或者我做錯了什麼?

理想的情況下,對我來說最直觀的東西是寫:

from Location loc where loc.Industries in (:ind) 

這不工作 - 它拋出一個錯誤,並說,它不知道的行業屬性。我猜是因爲工業作爲編程術語中的「財產」,實際上是DBMS方面的「關係」。

在HQL中編寫此查詢的最簡單和最有效的方法是什麼?

謝謝!

+0

有趣的問題。但是,您是否測量了有或沒有額外連接的查詢之間的顯着差異?也許它做了額外的連接來處理連接表中沒有外鍵約束和一些記錄引用不存在的行業的情況? –

+0

這是一個可能的解釋,但它似乎是一個很糟糕的解決方法,以解決數據不一致的問題,而這些數據不應該出現在設計良好且維護良好的數據庫中。似乎更可能這只是一個尚未實現的優化? –

回答

2

我不確定你可以避免這個額外的連接,因爲你已經使用了映射策略。

您可以通過使用中間類避開它,但是這將意味着你需要一個類的結構是這樣的:

public class Industry { 
    //Other stuff 
    public virtual List<LocationIndustry> LocationIndustries {get; set:;} 
} 

public class LocationIndustry { 
    public virtual Location Location {get; set;} 
    public virtual Industry Industry {get; set;} 
} 

public class Location { 
    //normal stuff 
    public virtual IList<LocationIndustry> LocationIndustries {get; set;} 
} 

然後你就可以在LocationIndustry類查詢,避免加盟Location

+0

+1,謝謝,但我已經考慮過這個選項,我覺得它很醜 - 我不想扭曲域模型並引入無用的實體;這也意味着當添加/刪除關聯時,我必須管理更多的對象並保持兩倍的關係。 (我開始認爲即使像NH這樣的怪物也無法處理阻抗不匹配的所有方面......) –

+0

事實上,這是您爲了靈活性交易表現的情況之一。你可以在這種情況下使用SQLQuery或命名查詢嗎?您可以在SQL中編寫查詢,並將其映射到對象。 –

+0

如果您使用的是nh3.1,則可以使用hql上新的'with'語法將in子句添加到連接中。然而,在與多對多關係一起使用時會出現這種錯誤。 –