使用Critieria API在NHibernate中选择子查询

时间:2011-06-30 21:19:03

标签: c# .net sql nhibernate

所以我有一个具有以下结构的SQL查询:

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]

我需要使用Criteria API在NHibernate中重新创建此查询。我尝试使用子查询API,但似乎要求内部查询返回单个列以检查与外部查询中的属性的相等性。但是,我回来了两个。我已经读过这可以通过HQL API完成,但我需要使用Criteria API来完成,因为我们将动态生成这样的查询。任何人都可以引导我走向正确的方向吗?

1 个答案:

答案 0 :(得分: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...));

我希望这有助于您的具体情况。

更新条件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版本)。

如果这对你有用,请告诉我。