Crinteria Únete marca E inserta de OR
Mi problema es que cuando configuro cb. O lo hace cb y .. cb es CriteriaBuilder Mi clase es:
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;
Mi código de criterios es:
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")))
);
El código genera:
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
)
¿Cómo puedo resolverlo? ¿Por qué mi código genera una declaración AND?
Respuestas
Probablemente se deba a que tiene un solo argumento en su llamada o método
cb.or(cb.equal(userJoin.get(ID_FIELD), root.get("id"))));
debiera ser
cb.or(arg1, arg2); // arg1 OR arg2
Lamento decirte que con criterios de API hoy no es posible, te contaré diferentes opciones:
1.- Utilizar consulta nativa
El uso de consultas nativas no es un problema ya que está utilizando cláusulas compatibles con todos los administradores de bases de datos
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();
En tu entidad
@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.- Use dos raíces, en caso de que la combinación interna le sirva en lugar de la combinación izquierda agregando las condiciones de la cláusula on en el 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)))
);
Como te estaba diciendo, aunque no se recomienda usar consultas nativas porque rompe con la filosofía JPA, en este caso como no usas las cláusulas de ninguna DB no debería ser un problema, yo sería la opción que haría escoger.