2017-10-05 6 views
0

Disons que j'ai une entité telle queagrégation dans Hibernate/JPA

@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; 
} 

Maintenant, je dois récupérer les dernières versions d'entités ayant des noms donnés et de la valeur de paramètre spécifique. En SQL j'écrire quelque chose comme ceci:

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

Mais, comment puis-je le fais avec Hibernate (de préférence en utilisant l'API critères)?

UPD:

Tout d'abord, comme il a été dit dans les commentaires, ma requête exemple est incorrect. La version correcte de ce que je cherche à atteindre ressemble plus à ceci:

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' 

Ma meilleure version de travail ce jour consiste à deux demandes distinctes:

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

BTW, probablement que je n'étais pas assez clair sur ce qui API de critères que je veux utiliser, c'est donc JPA.

Merci les gars pour les réponses, ils ont poussé de l'avant pour créer une solution laide, mais au moins fonctionnant.
J'apprécierai toute suggestion pour améliorer le code d'une telle tâche.

+0

d'abord corriger votre requête SQL avant de demander pour obtenir l'équivalent dans la requête de critères; Je ne pense pas que vous pouvez agréger sur un champ d'identification. – ujulu

+0

oui, vous avez raison - cette requête est incorrecte, elle vient du haut de ma tête juste pour cet exemple – user2256686

Répondre

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

Quelque chose comme ça devrait fonctionner. Qu'avez-vous essayé?

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

J'espère que cela fonctionne