es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Seleccionar la Clave Primaria de la entidad relacionada por OneToOne

Una entidad básica que tiene una referencia OneToOne a otra entidad:

@Entity
public class Amigo {

// ...

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Amigo mejorAmigo;

}

Me gustaría construir una consulta select que contenga algunos de los campos y el id del mejor amigo.
En SQL puro es trivial: SELECT bestfriendid FROM friend WHERE id = 123

Con el API de criterios de JPA las cosas se vuelven muy interesantes:

EntityManager em = …
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(Tuple.class);
Root root = query.from(Friend.class);
query.multiselect(root.get(Friend_.bestFriend).get(Friend_.id), root.get(Friend_.name));
query.where(cb.equal(root.get(Friend_.id), id));
return em.createQuery(query).getSingleResult();

Esto funciona para un amigo con un mejor amigo configurado, pero el SQL generado es tonto: SELECT t0.ID, t1.NAME FROM FRIEND t0, FRIEND t1 WHERE ((t1.ID = ?) AND (t0.ID = t1.BESTFRIEND_ID))
Tampoco funciona en un amigo que no tiene mejor amigo.
Me gustaría ver un simple SELECT t0.NAME, t0.BESTFRIEND_ID FROM FRIEND t0 WHERE t0.ID = ?.

¿Se puede cambiar root.get(Friend_.bestFriend).get(Friend_.id) por algo más para lograr esto?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, para obtener una consulta SQL más simple, puedes usar un left join en lugar de un multiselect. Aquí tienes un ejemplo:

    EntityManager em = ...
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<tuple> query = cb.createTupleQuery();
    Root<friend> root = query.from(Friend.class);
    Join<friend, friend=""> bestFriendJoin = root.join(Friend_.bestFriend, JoinType.LEFT);
    query.select(cb.tuple(root.get(Friend_.name), bestFriendJoin.get(Friend_.id)));
    query.where(cb.equal(root.get(Friend_.id), id));
    return em.createQuery(query).getSingleResult();
    

    Esto debería generar la consulta SQL deseada: SELECT t0.NAME, t0.BESTFRIEND_ID FROM FRIEND t0 LEFT OUTER JOIN FRIEND t1 ON (t0.BESTFRIEND_ID = t1.ID) WHERE (t0.ID = ?). Además, esta consulta funcionará incluso si un amigo no tiene un mejor amigo debido al left join.</friend,>

Comments are closed.