假设我有两张桌子,书籍和评论。评论有一个列,星星,可以有1到5之间的值。一本书可以有很多评论。
我如何选择所有图书,以便使用Criteria API返回每本图书的最高和最低3评论(而不是所有评论)?
如果Criteria API不具备,我可以提供其他建议,如HQL,SQL等。
答案 0 :(得分:18)
您可以随时设置排序asc / desc,然后限制结果。
例如:
criteria.addOrder(Order.desc("id"));
criteria.setMaxResults(1);
不确定效率方面的立场。我假设在Select *
被解雇之后它正在进行过滤?
答案 1 :(得分:13)
试试这个,让我知道它是否适合你:
// you should have the DAO class containing this queries
// extend HibernateDaoSupport
List<Tag> topList = getSession().createQuery("FROM Reviews r WHERE r.book = "
+ book + " ORDER BY r.stars asc").setMaxResults(3).list();
List<Tag> bottomList = getSession().createQuery("FROM Reviews r WHERE r.book = "
+ book + " ORDER BY r.stars desc").setMaxResults(3).list();
答案 2 :(得分:5)
回答我自己的问题......
我真的很惊讶这是多么困难。所有涉及查询书籍的解决方案和每本书的顶部和底部评论列表都会导致某些数据库中每本书的N个查询,特别是我的(MySql)需要3N。当然,有人可能能够找到一个聪明的方法来解决这个问题,但是我使用代码,原始SQL,研究其他人所做的事情,数据库限制等似乎总是会回到原点。
所以......我最终解决了这个问题。每当我查询书籍时(这是一个非常频繁的查询 - 仅供参考的FYI书籍/评论 - 实际的域名不同)我不计算顶部和底部评论。我会在提交新评论时计算顶部/底部。这会将审核从一个“查询”提交到三个查询,但与查询书籍相比,提交审核的次数相当少。
为此,我在Book,topReviews和bottomReviews中添加了两个新属性,并将它们映射为Review上的一对多列表。然后,我更新了保存新评论的代码,以查询相关图书的顶部和底部评论(2个查询),设置图书上的顶部/底部评论属性(覆盖前一个),并保存图书。任何书籍查询现在返回这些“缓存”的顶部和底部评论。我仍然有一个懒惰的“评论”属性,如果需要,将包含所有评论(不仅仅是顶部/底部) - 另一个一对多映射。
我愿意接受其他建议。这里的大多数答案都在球场,但由于数据库限制或需要太多查询而错过了问题或无法解决问题。
答案 3 :(得分:1)
这通常是通过类似联合的东西来完成的,你在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();
答案 4 :(得分:0)
我认为您无法使用单个查询执行所需操作。你当然可以用两个来做(但是使用带有命名参数的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;
当然,您可以编写一个简单的辅助方法来进行这两个调用,并将结果整理成您喜欢的任何数据结构。
答案 5 :(得分:0)
如何将Review and Book的映射作为多对多,然后在Book的评论集合中指定:order-by =“rating desc”,lazy =“true”
假设使用lazy-fetching方法,只有在从集合中提取对象时才会获取数据,但我不确定这一点。要确认,您可以打开Hibernate SQL日志记录并监视在运行时进行的查询。
答案 6 :(得分:0)
使用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<YourEntity, String> {
@Query("FROM YourEntity")
List<YourEntity> findTopOrderByYourEntity(Pageable pageable);
}