J'essaie de construire des requêtes de manière dynamique, et ma prochaine cible est d'ajouter des clauses JOIN (je ne sais pas comment utiliser l'API).
À ce jour, par exemple, ce code fonctionne pour moi:
...
Class baseClass;
...
CriteriaBuilder cb = JpaHandle.get().getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(this.baseClass);
Root entity_ = cq.from(this.baseClass);
Predicate restrictions = null;
...
restrictions = cb.conjunction();
restrictions = cb.and(restrictions, entity_.get("id").in(this.listId));
...
cq.where(restrictions);
...
Query qry = JpaHandle.get().createQuery(cq);
(Remarque: JpaHandle provient de la mise en œuvre de Wicket-JPA)
Mon désir est d'ajouter une clause JOIN (aussi générique que possible)!
J'ai les annotations particulières dans les classes (this.baseClass)
Par exemple :
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "assay_id", nullable = false)
Alors, existe-t-il un moyen de quelque chose comme ça dans la JPA standard? (Remarque: cela ne compile pas)
Voici quelques approches d'échec pratiques:
...
Join<Experiment,Assay> experimentAssays = entity_.join( entity_.get("assay_id") );
Ou comme ça:
...
CriteriaQuery<Customer> q = cb.createQuery(Customer.class);
Root<Customer> c = q.from(Customer.class);
SetJoin<Customer, PurchaseOrder> o = c.join(Customer_.orders);
Pour moi, si ça pouvait être plus générique que possible ce sera génial ...:
...
Join joinClause = entity_join(entity_.get("assay_id"), entity2_.get("id"));
Bien sûr, j'ai les annotations particulières dans les classes (this.baseClass)
Merci pour votre temps. J'apprécierai toutes sortes de commentaires!
Peut-être que l'extrait suivant du Chapitre 23 - Utilisation de l'API Criteria pour créer des requêtes du tutoriel Java EE 6 jettera un peu de lumière (en fait, je suggère de lire le tout Chapitre 23):
Recherche de relations à l'aide de jointures
Pour les requêtes qui accèdent aux classes d'entités liées, la requête doit définir une jointure à l'entité associée en appelant l'un des
From.join
méthodes sur l'objet racine de la requête ou un autre objetjoin
. Les méthodes de jointure sont similaires au mot cléJOIN
dans JPQL.La cible de la jointure utilise la classe Metamodel de type
EntityType<T>
pour spécifier le champ persistant ou la propriété de l'entité jointe.Les méthodes de jointure renvoient un objet de type
Join<X, Y>
, oùX
est l'entité source etY
est la cible de la jointure.Exemple 23-10 Joindre une requête
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class); Metamodel m = em.getMetamodel(); EntityType<Pet> Pet_ = m.entity(Pet.class); Root<Pet> pet = cq.from(Pet.class); Join<Pet, Owner> owner = pet.join(Pet_.owners);
Les jointures peuvent être chaînées ensemble pour naviguer vers les entités liées de l'entité cible sans avoir à créer un
Join<X, Y>
instance pour chaque jointure.Exemple 23-11 Le chaînage se joint à une requête
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class); Metamodel m = em.getMetamodel(); EntityType<Pet> Pet_ = m.entity(Pet.class); EntityType<Owner> Owner_ = m.entity(Owner.class); Root<Pet> pet = cq.from(Pet.class); Join<Owner, Address> address = cq.join(Pet_.owners).join(Owner_.addresses);
Cela étant dit, j'ai quelques remarques supplémentaires:
Tout d'abord, la ligne suivante dans votre code:
Root entity_ = cq.from(this.baseClass);
Cela me fait penser que vous avez en quelque sorte manqué la partie Classes de métamodèles statiques. Classes de métamodèle telles que Pet_
dans l'exemple cité sont utilisés pour décrire les méta-informations d'une classe persistante. Ils sont généralement générés à l'aide d'un processeur d'annotation ( classes de métamodèles canoniques) ou peuvent être écrits par le développeur (métamodèle non canonique). Mais votre syntaxe a l'air bizarre, je pense que vous essayez d'imiter quelque chose que vous avez manqué.
Deuxièmement, je pense vraiment que vous devriez oublier cela assay_id
clé étrangère, vous êtes sur le mauvais chemin ici. Vous devez vraiment commencer à penser à l'objet et à l'association, pas aux tables et aux colonnes.
Troisièmement, je ne suis pas vraiment sûr de comprendre ce que vous voulez dire exactement en ajoutant une clause JOIN aussi générique que possible et à quoi ressemble votre modèle d'objet, puisque vous ne l'avez pas fourni (voir précédent point). Il est donc tout simplement impossible de répondre plus précisément à votre question.
Pour résumer, je pense que vous avez besoin de lire un peu plus sur les critères JPA 2.0 et l'API Metamodel et je recommande vivement les ressources ci-dessous comme point de départ.
En fait, vous n'avez pas à gérer le métamodèle statique si vos annotations étaient correctes.
Avec les entités suivantes:
@Entity
public class Pet {
@Id
protected Long id;
protected String name;
protected String color;
@ManyToOne
protected Set<Owner> owners;
}
@Entity
public class Owner {
@Id
protected Long id;
protected String name;
}
Vous pouvez utiliser ceci:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> petMetaModel = m.entity(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(petMetaModel.getSet("owners", Owner.class));
Vous n'avez pas besoin d'apprendre JPA. Vous pouvez utiliser mes critères faciles pour JPA2 ( https://sourceforge.net/projects/easy-criteria/files/ ). Voici l'exemple
CriteriaComposer<Pet> petCriteria CriteriaComposer.from(Pet.class).
where(Pet_.type, EQUAL, "Cat").join(Pet_.owner).where(Ower_.name,EQUAL, "foo");
List<Pet> result = CriteriaProcessor.findAllEntiry(petCriteria);
OR
List<Tuple> result = CriteriaProcessor.findAllTuple(petCriteria);
Attention! Il y a un certain nombre d'erreurs sur l'exemple de Sun JPA 2 et le contenu collé résultant dans la réponse de Pascal. Veuillez consulter cet article .
Ce message et l'exemple Sun Java EE 6 JPA 2 ont vraiment retenu ma compréhension de JPA 2. Après avoir parcouru les manuels Hibernate et OpenJPA et pensé que j'avais une bonne compréhension de JPA 2, je encore confus après en revenant à ce poste.