2011-06-30 46 views
4

所以我有以下結構的SQL查詢:選擇在NHibernate的子查詢與Critieria API

select p.* from 
(
    select max([price]) as Max_Price, 
    [childId] as childNodeId 
    from [Items] group by [childId] 
) as q inner join [Items] as p on p.[price] = q.[Max_Price] and p.[childId] = q.[childNodeId] 

我需要重新在該NHibernate的查詢,使用標準的API。我嘗試過使用Subqueries API,但它似乎要求內部查詢返回單個列以檢查外部查詢中的屬性是否相等。但是,我返回兩個。我讀過這可以通過HQL API完成,但我需要使用Criteria API來完成,因爲我們將動態地生成這樣的查詢。任何人都可以在這裏指引我正確的方向嗎?

回答

14

我設法通過稍微調整原始的sql查詢來解決類似的問題。我已經結束了像這樣的東西(僞SQL代碼):

SELECT p.* FROM [Items] as p 
WHERE EXISTS 
(
    SELECT [childId] as childNodeId FROM [Items] as q 
    WHERE p.[childId] = q.[childNodeId] 
    GROUP BY q.[childId] 
    HAVING p.[price] = MAX(q.[price]) 
) 

這是QueryOver實現:

var subquery = QueryOver.Of(() => q) 
    .SelectList(list => list.SelectGroup(() => q.ChildId)) 
     .Where(Restrictions.EqProperty(
      Projections.Property(() => p.Price), 
      Projections.Max(() => q.Price))) 
     .And(Restrictions.EqProperty(
      Projections.Property(() => p.ChildId), 
      Projections.Property(() => q.ChildId))); 

從這裏你只需要通過別名,以便NHibernate的可以解決實體正確(僞代碼):

var filter = QueryOver.Of(() => p) 
    .WithSubquery.WhereExists(GetSubQuery(p, criteria...)); 

我希望這有助於您的具體情況。

UPDATE:標準API

var subquery = DetachedCriteria.For<Items>("q") 
    .SetProjection(Projections.ProjectionList() 
     .Add(Projections.GroupProperty("q.ChildId"))) 
    .Add(Restrictions.EqProperty("p.Price", Projections.Max("q.Price"))) 
    .Add(Restrictions.EqProperty("p.ChildId", "q.ChildId")); 

var query = DetachedCriteria.For<Items>("p") 
    .Add(Subqueries.Exists(subquery)); 

不過我會建議堅持到QueryOver版本,它更加直觀,您避免魔術字符串(特別是你沒有升級NH版) 。

請讓我知道這是否適合你。

+0

我有點困惑。有沒有辦法使用ICriteria API而不是QueryOver來做到這一點?我之前沒有使用QueryOver,這可能是一個複雜的「第一個示例」:\ – GWLlosa

+0

@GWLlosa:您能否確認我發佈在我的答案中的SQL適用於您,並且您得到完全相同的結果?我可以比嘗試用Criteria API重新編寫查詢,btw使用哪個版本的NHibernate? – MonkeyCoder

+0

您擁有的SQL和我所做的SQL實際上會生成相同的行。根據DLL的細節,我使用NHibernate 3.1.0.4000。 – GWLlosa