Crinteria Join marque ET incrustation de OU
Mon problème est que lorsque je mets cb.or it do cb et .. cb est CriteriaBuilder Ma classe est:
public class User extends BaseEntity<User> {
public static final String CHILDREN_FIELD = "children";
public static final String PARENT_FIELD = "parent";
//Id column based in BaseEntity
OneToOne(fetch = LAZY)
JoinColumn(name = "parent_partner_id")
User parent;
OneToMany(mappedBy = "parent", fetch = LAZY,cascade = {})
private List<User> children;
Mon code de critères est:
Root<User> root = query.from(User.class);
Join<User, User> userJoin = root.join(CHILDREN_FIELD, JoinType.LEFT);
userJoin.on(
cb.or(
cb.equal(userJoin.get(ID_FIELD), root.get("id")))
);
Le code génère:
select
user0_.id as col_0_0_
from
user user0_
left outer join
user children2_
on user0_.id=children2_.parent_id
and ( <- i write OR in cb!! why it generates AND ?
children2_.id=user0_.id
)
Comment puis-je le résoudre? Pourquoi mon code génère une instruction AND?
Réponses
C'est probablement parce que vous avez un seul argument dans votre appel de méthode ou
cb.or(cb.equal(userJoin.get(ID_FIELD), root.get("id"))));
devrait être
cb.or(arg1, arg2); // arg1 OR arg2
Je suis désolé de vous dire qu'avec les critères API ce n'est pas possible aujourd'hui, je vais vous parler des différentes options:
1.- Utiliser la requête native
L'utilisation de la requête native n'est pas un problème car vous utilisez des clauses prises en charge par tous les gestionnaires de bases de données
List<User> result = em.createNativeQuery("select * from user p "+
"left outer join user p1 on p.id = p1.parent_id or p.id = p1.id",
"User.nativeConstructorMapping").getResultList();
Dans votre entité
@SqlResultSetMappings({
@SqlResultSetMapping(name="User.nativeConstructorMapping",
classes = {
@ConstructorResult(
targetClass = Users.class,
columns = {
@ColumnResult(name = "id", type = Long.class),
@ColumnResult(name = "name", type = String.class)
[...]
})
})
})
....
public User(Long id, String name, [...]) {
super();
this.id= id;
this.name = name
[...]
}
2.- Utilisez deux racines, au cas où la jointure interne vous servirait au lieu de la jointure gauche en ajoutant les conditions de la clause on dans le where
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root1 = query.from(User.class);
Root<User> root2 = query.from(User.class);
query.where(cb.or(
cb.equal(root1.get(User_.id),root2.get(User_.parent).get(User_.id)),
cb.equal(root1.get(User_.id),root2.get(User_.id)))
);
Comme je vous le disais, bien qu'il ne soit pas recommandé d'utiliser des requêtes natives car cela rompt avec la philosophie JPA, dans ce cas, comme vous n'utilisez les clauses d'aucune base de données, cela ne devrait pas poser de problème, je serais l'option que je voudrais choisir.