web-dev-qa-db-fra.com

Comment faire pour joindre un CriteriaBuilder avec une condition "on" personnalisée?

Je veux faire une requête où je joins 2 tables, en utilisant le CriteriaBuilder. Dans MySQL, la requête que j'essaie de faire ressemblerait à ceci:

SELECT * FROM order
LEFT JOIN item
ON order.id = item.order_id
AND item.type_id = 1

Je veux obtenir toutes les commandes et si elles ont un article de type # 1, je veux rejoindre cet article. Cependant, si aucun article de type # 1 n'est trouvé, je veux toujours obtenir la commande. Je ne peux pas comprendre comment faire cela avec le CriteriaBuilder. Tout ce que je sais faire, c'est:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> order = cq.from(Order.class);
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT);
Join<Item, Type> type = order.join(Item_.type, JoinType.LEFT);
cq.select(order);
cq.where(cb.equal(type.get(Type_.id), 1));

Cette requête est rompue, car elle aboutit à quelque chose comme ceci dans MySQL:

SELECT * FROM order
LEFT JOIN item
ON order.id = item.order_id
WHERE item.type_id = 1

Le résultat ne contiendra que des commandes avec des articles de type # 1. Les commandes sans sont exclues. Comment puis-je utiliser le CriteriaBuilder pour créer une requête comme dans le premier exemple?

23
Bjørn Stenfeldt

C'est possible en utilisant la méthode onJoin<Z, X> on(Predicate... restrictions);

Voici comment:

Root<Order> order = cq.from(Order.class);
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT);
item.on(cb.equal(item.get(Item_.type), 1));
19
hzitoun

Je pense que c'est le même problème que celui posé dans cette question. Il semble que ce ne soit pas possible dans CriteriaBuilder. C'est possible dans l'API Hibernate Criteria, mais cela ne vous aidera probablement pas.

API de critères JPA: condition multiple sur LEFT JOIN

1
carbontax

La clause ON est prise en charge dans la version Hibernate 4.3, tout le monde sait s'il existe un problème d'indexation des paramètres entre l'index des paramètres des conditions personnalisées supplémentaires avec l'index des filtres de mappage existants lors d'une jointure externe avec la clause ON?

En utilisant la classe d'entité Person ci-dessous comme exemple, disons que j'ajoute ce filtre pour limiter les types d'adresses et que le filtre est activé pour remplir la clause IN. L'index des paramètres de la clause IN provoquera le problème [2] lorsque j'ajouterai des conditions supplémentaires (telles que l'utilisation de la colonne "rue") de la clause ON. Est-ce un problème connu?

[1] @Filter (name = "addressTypes", condition = "ADDRESS_TYPE in (: supportedTypes)"))

[2] Causée par: ERREUR 22018: format de chaîne de caractères non valide pour le type BIGINT. Définir des adresses privées;

0
user3390708

Il existe une solution de contournement si vous utilisez Hibernate 3.6 avec JPA 2.0. Ce n'est pas la meilleure solution, mais cela fonctionne parfaitement pour moi.

J'ai dupliqué l'entité avec l'annotation @Where hibernate. Cela signifie que chaque fois que vous utilisez la jointure avec cette entité, hibernate ajoutera la condition supplémentaire sur l'instruction join au SQL généré.

Par exemple, nous avons initialement l'exemple suivant:

@Entity
@Table(name = "PERSON")
public class Person {

    @Id
    @Column(name = "PERSON_ID")
    private Long id;

    @Id
    @Column(name = "PERSON_NAME")
    private String name;

   @OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
   private Set<Address> addresses;

}

@Entity
@Table(name = "ADDRESS")
public class Address {

    @Id
    @Column(name = "ADDRESS_ID")
    private Long id;

    @Id
    @Column(name = "ADDRESS_STREET")
    private String street;

   @ManyToOne
   @JoinColumn(name = "PERSON_ID")
    private Person person;

}

Afin d'ajouter des conditions supplémentaires aux critères Join, nous devons dupliquer le mappage Address @Entity, en ajoutant l'annotation @Where @Where (clause = "ADDRESS_TYPE_ID = 2").

@Entity
@Table(name = "ADDRESS")
@Where(clause = " ADDRESS_TYPE_ID = 2")
public class ShippingAddress {

    @Id
    @Column(name = "ADDRESS_ID")
    private Long id;

    @Id
    @Column(name = "ADDRESS_STREET")
    private String street;

   @OneToOne
   @JoinColumn(name = "PERSON_ID")
    private Person person;

}

De plus, nous devons ajouter l'association de mappage en double pour la nouvelle entité.

@Entity
@Table(name = "PERSON")
public class Person {

    @Id
    @Column(name = "PERSON_ID")
    private Long id;

    @Id
    @Column(name = "PERSON_NAME")
    private String name;

   @OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
   private Set<Address> addresses;

   @OneToOne(mappedBy = "person")
   private ShippingAddress shippingAddress;

}

Enfin, vous pouvez utiliser une jointure avec cette entité spécifique dans vos critères:

PersonRoot.join(Person_.shippingAddress, JoinType.LEFT);

Le code Hibernate Snippet SQL devrait ressembler à ceci:

 left outer join
        address shippingadd13_ 
            on person11_.person_id=shippingadd13_.person_id 
            and (
                shippingadd13_.ADDRESS_TYPE_ID = 2 
            ) 
0
Eduardo Fabricio

Je sais que cette question a été posée depuis longtemps, mais récemment, j'ai eu le même problème et j'ai trouvé cette solution à partir d'un forum Oracle, j'ai copié et collé juste au cas où le lien ne serait plus disponible.

MiguelChillitupaArmijos 29-abr-2011 1:41 (en respuesta a 840578) Pensez que vous devriez utiliser quelque chose comme:

em.createQuery("SELECT DISTINCT e.Id" +
                    " from Email e " +
                    " left join e.idEmailIn e2 *with* e2.responseType = 'response'" +
                    "     where e.type = 'in' and e.responseMandatory = true").getSingleResult(); 

Et c'est le lien.

Critères JPA: LEFT JOIN avec une condition AND

0
OJVM