hibernate选择具有条件的顶部和底部n行

假设我有两张桌子,书籍和评论。 评论有一个列,星星,可以有1到5之间的值。一本书可以有很多评论。

我如何选择所有书籍,以便使用Criteria API返回每本书的顶部和底部3评论(而不是所有评论)?

如果Criteria API不具备,我可以使用其他建议,如HQL,SQL等。

您始终可以设置排序asc / desc,然后限制结果。

例如:

criteria.addOrder(Order.desc("id")); criteria.setMaxResults(1); 

不确定它在效率方面的立场。 我假设在Select *被触发后它正在进行过滤?

试试这个,让我知道它是否适合你:

  // you should have the DAO class containing this queries // extend HibernateDaoSupport List topList = getSession().createQuery("FROM Reviews r WHERE r.book = " + book + " ORDER BY r.stars asc").setMaxResults(3).list(); List bottomList = getSession().createQuery("FROM Reviews r WHERE r.book = " + book + " ORDER BY r.stars desc").setMaxResults(3).list(); 

回答我自己的问题……

我真的很惊讶这是多么困难。 所有涉及查询书籍的解决方案和每本书的顶部和底部评论列表都会导致某些数据库中的每本书有N个查询,特别是我的(MySql)需要3N。 当然,有人可能能够找到一个聪明的方法,但我玩代码,原始SQL,研究其他人做了什么,数据库限制等似乎总是回到那一点。

所以……我最终解决了这个问题。 每当我查询书籍时这不是计算顶部和底部的评论(这是一个非常频繁的查询 – 仅供参考的FYI书籍/评论 – 实际域名不同)我会在提交新评论时计算顶部/底部。 这会将审核从一个“查询”提交到三个查询,但与查询“书籍”相比,提交“审核”的次数相当少。

为此,我向Book,topReviews和bottomReviews添加了两个新属性,并将它们映射为Review上的一对多列表。 然后,我更新了保存新评论的代码,以查询相关图书的顶部和底部评论(2个查询),设置图书上的顶部/底部评论属性(覆盖前一个),并保存图书。 任何书籍查询现在返回这些“缓存”的顶部和底部评论。 我仍然有一个懒惰的“评论”属性,如果需要,将包含所有评论(不仅仅是顶部/底部) – 另一个一对多映射。

我对其他建议持开放态度。 这里的大多数答案都在球场,但由于数据库限制或需要太多查询而错过了问题或无法工作。

这通常是通过诸如union之类的东西完成的,你在HQL中无法做到这一点。

但是,您可以在HQL中执行此操作

 WHERE id in ([SELECT top 3]) or id in ([SELECT bottom 3]) 

我没有办法测试这个,但这也可能有用。

 DetachedCriteria topN = [ your criteria ] DetachedCriteria bottomN = [ your criteria ] session.createCriteria(..._ .add( Property.or(Property.forName("id").in(topN),Property.forName("id").in(bottomN) ) .list(); 

我不认为你可以使用单个查询做你想做的事。 你当然可以用两个来做(但是使用带有命名参数的EJBQL):

 SELECT r FROM Reviews r WHERE r.book = :book ORDER BY r.stars ASC LIMIT 3; SELECT r FROM Reviews r WHERE r.book = :book ORDER BY r.stars DESC LIMIT 3; 

当然,您可以编写一个简单的辅助方法来进行这两个调用,并将结果整理到您喜欢的任何数据结构中。

如何将Review和Book的映射作为多对多,然后在Book的评论集合中指定:order-by =“rating desc”,lazy =“true”

假设使用延迟获取方法,只有在从集合中提取对象时才会获取数据,但我不确定这一点。 要确认,您可以打开Hibernate SQL日志记录并监视在运行时进行的查询。

使用org.springframework.data.domain.Pageable的两个HQL查询如下:

在中间层服务之前,您创建可分页和调用repo:

 Pageable pageableTop = new PageRequest(0, 3, Direction.ASC, "yourFieldToSortBy"); yourRepository.findTopOrderByYourEntity(pageableTop); Pageable pageableBottom = new PageRequest(0, 3, Direction.DESC, "yourFieldToSortBy"); yourRepository.findTopOrderByYourEntity(pageableBottom); 

回购:

 public interface YourRepository extends CrudRepository { @Query("FROM YourEntity") List findTopOrderByYourEntity(Pageable pageable); }