使用NHibernate的Criteria API选择子查询

5

我有一个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中重新创建此查询。 我尝试使用Subqueries API,但似乎要求内部查询返回单个列以检查与外部查询中的属性相等性。 然而,我返回了两个列。 我已经阅读到可以通过HQL API实现此目的,但我需要使用Criteria API进行操作,因为我们将动态生成此类查询。 有人可以指导我正确的方向吗?
1个回答

14

我成功地解决了一个类似的问题,通过稍微调整原始的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...));

希望这能对你的特定情况有所帮助。

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

如果这对您起作用,请告诉我。


我有点困惑。是否有一种使用 ICriteria API 而不是 QueryOver 来完成这个任务的方法?我以前没有使用过 QueryOver,这可能是一个复杂的“第一个示例” :\ - GWLlosa
@GWLlosa:您能确认我在答案中发布的SQL对您有效,并且您获得完全相同的结果吗?然后我可以尝试使用Criteria API重新编写查询,顺便问一下,您使用的是哪个版本的NHibernate? - MonkeyCoder
你所拥有的SQL和我所拥有的SQL实际上产生了相同的行。根据DLL详细信息,我正在使用NHibernate 3.1.0.4000。 - GWLlosa
@GWLlosa:请查看我使用 Criteria API 版本的更新。 - MonkeyCoder
太棒了!我之前忽略的关键是,我可以在属性和投影之间添加EqProperty限制。为了与现有代码保持一致,我们使用ICriteria;否则,我同意QueryOver更加简洁。 - GWLlosa
你能解释一下在使用QueryOver时如何附加子查询吗? 我尝试了session.QueryOver(() => p).WithSubquery.WhereExists(subquery) 但是它抛出了一个异常,说找不到父属性(例如p.ChildId)。 - H77

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接