有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Hibernate/JPA中的java聚合

假设我有一个实体,比如

@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)做到这一点呢

UPD:

首先,正如评论中所说,我的示例查询是不正确的。我试图实现的目标的正确版本更像这样:

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();

顺便说一句,我可能不太清楚我想使用哪种标准API,所以是JPA

谢谢你们的回答,他们已经努力创造出丑陋但至少有效的解决方案
我将感谢任何关于如何改进此类任务代码的建议


共 (2) 个答案

  1. # 1 楼答案

    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();
    

    我希望这能奏效

  2. # 2 楼答案

    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()
    

    这样的办法应该行得通。你试过什么