2010-08-30 4 views
1

Je suis bloqué par un problème concernant les requêtes JPA-2.0 avec les relations. Comment serait-il possible de sélectionner un Dataset avec au moins un Event avec type = B?JPA-2.0 Simple Select-Where question

@Entity 
class Dataset { 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "dataset") 
    public List<Event> events; 
} 

@Entity 
class Event { 
    @ManyToOne 
    @JoinColumn 
    public Dataset dataset; 

    public Type type; 
} 

enum Type { 
    A, B, C 
} 

Mon point de départ est

CriteriaBuilder _builder = em.getCriteriaBuilder(); 
CriteriaQuery<Dataset> _criteria = _builder.createQuery(Dataset.class); 

// select from 
Root<Dataset> _root = _criteria.from(Dataset.class); 
_criteria.select(_root); 

// apply some filter as where-clause (visitor) 
getFilter().apply(
    _root, _criteria, _builder, em.getMetamodel() 
); 

// how to add a clause as defined before? 
... 

Toutes les idées sur ce sujet. J'ai essayé de créer une sous-requête ainsi qu'une jointure, mais je l'ai mal fait et j'ai toujours obtenu tous les jeux de données comme résultat.

Répondre

4

Essayez

SELECT d FROM DataSet d WHERE EXISTS 
    (SELECT e FROM Event e WHERE e.dataSet = d and e.type = :type) 

EDIT: Comme Pascal a fait remarquer il semble que vous utilisez l'API de critères. Pas aussi familier avec ça, mais je vais avoir un coup de poignard.

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<Dataset> criteria = builder.createQuery(Dataset.class); 

Root<Dataset> root = criteria.from(Dataset.class); 
criteria.select(root); 

// build the subquery 
SubQuery<Event> subQuery = criteria.subQuery(Event.class); 
Root<Event> eventRoot = subQuery.from(Event.class); 
subQuery.select(eventRoot); 

ParameterExpression<String> typeParameter = builder.parameter(String.class); 
Predicate typePredicate = builder.equal(eventRoot.get(Event_.type), typeParameter)); 

// i have not tried this before but I assume this will correlate the subquery with the parent root entity 
Predicate correlatePredicate = builder.equal(eventRoot.get(Event_.dataSet), root); 
subQuery.where(builder.and(typePredicate, correlatePredicate); 

criteria.where(builder.exists(subQuery))); 

List<DataSet> dataSets = em.createQuery(criteria).getResultList(); 

Ouf c'était dur travail. Je retourne à Linq maintenant.

+0

Il semble que l'OP essaie d'utiliser l'API Criteria ici. –

+0

Merci, ça a marché pour moi. J'ai aussi compris pourquoi mon approche a échoué. J'ai essayé de réutiliser une requête déjà exécutée et ajouté une autre clause. Hibernate ne s'en est pas plaint, mais a généré de faux alias (la requête principale et la sous-requête avaient le même alias, ce qui échoue évidemment). – Jan

+0

Vous devez ajouter 'subquery.select (eventRoot);' ainsi que vérifier vos parenthèses au prédicat 'correlatePredicate'. Enfin le 'builder.not (builder.exists (subQuery))' aurait du être sans _not_. Merci beaucoup pour votre aide. – Jan