【发布时间】: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