【问题标题】:Aggregation in Hibernate / JPAHibernate / JPA 中的聚合
【发布时间】:2017-10-05 17:17:42
【问题描述】:

假设我有一个实体,例如

@Entity
@Table(name = "t_entity")
Entity {

   @Id
   @GeneratedValue
   @Column(name = "id")
   int id;

   @Column(name = "name")
   String name;

   @Column(name = "version")
   int version;

   @Column(name = "parameter")
   String parameter;
}

现在,我需要获取具有给定名称和特定参数值的实体的最新版本。在普通的 SQL 中,我会这样写:

select id, name, max(version) version, parameter
from entity 
where name in ('foo', 'bar') and parameter = 'baz'
group by name, id

但是,我该如何使用 Hibernate(最好使用 Criteria API)来做到这一点?

更新:

首先,正如 cmets 中所述,我的示例查询不正确。我试图实现的正确版本看起来更像这样:

select e0.id, e0.name, e0.version, e0.parameter from entity e0 
right join (select name, max(version) mv from entity where name in ('foo', 'bar') group by name) e1 
on e0.name = e1.name and e0.versioin = e1.mv
where e0.parameter = 'baz'

到目前为止,我最好的工作版本涉及两个单独的请求:

CriteriaBuilder cb = sessionFactory.getCriteriaBuilder();

CriteriaQuery<Tuple> lvq = cb.createQuery(Tuple.class);
Root<Entity> lvr = lvq.from(Entity.class);

lvq.multiselect(lvr.get("name").alias("name"), cb.max(lvr.get("version")).alias("mv"));
lvq.where(lvr.get("name").in("foo", "bar"));
lvq.groupBy(lvr.get("name"));

List<Tuple> lv = sessionFactory.getCurrentSession().createQuery(lvq).getResultList();

CriteriaQuery<Entity> cq = cb.createQuery(Entity.class);
Root<Entity> root = cq.from(Entity.class);

List<Predicate> lvp = new LinkedList<>();
for (Tuple tuple : lv) {
    lvp.add(cb.and(
        cb.equal(root.get("version"), tuple.get("mv")),
        cb.equal(root.get("name"), tuple.get("name"))));
}

cq.select(root).where(cb.and(
        cb.equal(root.get("parameter"),"baz"), 
        cb.or(lvp.toArray(new Predicate[lvp.size()])));

return sessionFactory.getCurrentSession().createQuery(cq).getResultList();

顺便说一句,我可能不太清楚我想使用哪个 Criteria API,所以它是 JPA。

感谢你们的回答,他们一直在努力创造丑陋但至少可行的解决方案。
对于如何改进此类任务的代码,我将不胜感激。

【问题讨论】:

  • 首先更正您的 SQL 查询,然后再要求在条件查询中获取等效项;我认为您不能在 ID 字段上进行聚合。
  • 是的,你是对的 - 这个查询是不正确的,它来自我的头脑只是为了这个例子

标签: java hibernate jpa criteria-api


【解决方案1】:
createCriteria(Entity.class).add(Restrictions.in("name", new String[] {"foo","bar"})).add(Restrictions.eq("parameter","baz")).add( Projections.groupProperty("name")).add(Projections.groupProperty("id")).list()

这样的事情应该可以工作。你试过什么?

【讨论】:

    【解决方案2】:
    Criteria criteria = session.createCriteria(Entity.class,"entity");
    criteria
    .add(Restrictions.in("name", new String[] {"foo","bar"}))
    .add(Restrictions.eq("parameter","baz"))
    .setProjection(Projections.projectionList()
    .add(Projections.property("name"), "name")
    .add(Projections.property("id"), "id")
    .add(Projections.max("version"))
    .add(Projections.groupProperty("name"))
    .add(Projections.groupProperty("id"))
    .list();
    

    我希望这行得通

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      • 1970-01-01
      • 2013-04-26
      • 2012-01-06
      • 1970-01-01
      相关资源
      最近更新 更多