Tengo las siguientes entidades; El ticket contiene un conjunto de 0, N WorkOrder:Criterio API: recuperación de una lista devuelve entidad principal repetida
@Entity
public class Ticket {
...
@OneToMany(mappedBy="ticket", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<WorkOrder> workOrders = null;
...
}
@Entity
public class WorkOrder {
...
@ManyToOne
@JoinColumn(nullable = false)
private Ticket ticket;
}
Estoy cargando Billetes y obteniendo los atributos. Todos los atributos 0,1 no presentan ningún problema. Para workOrders, utilicé this answer para obtener el siguiente código.
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<Ticket> criteriaQuery = criteriaBuilder
.createQuery(Ticket.class);
Root<Ticket> rootTicket = criteriaQuery.from(Ticket.class);
ListAttribute<? super Ticket, WorkOrder> workOrders =
rootTicket.getModel().getList("workOrders", WorkOrder.class);
rootTicket.fetch(workOrders, JoinType.LEFT);
// WHERE logic
...
criteriaQuery.select(rootTicket);
TypedQuery<Ticket> query = this.entityManager.createQuery(criteriaQuery);
return query.getResultList();
El resultado es que, en una consulta que me debería devolver 1 entradas con 5 órdenes de trabajo, estoy recuperando el mismo billete 5 veces.
Si acabo de hacer que los workOrders sean un Fetch ansioso y elimine el código de búsqueda, funciona como debería.
¿Alguien me puede ayudar? Gracias por adelantado.
ACTUALIZACIÓN:
Una explicación acerca de por qué no estoy feliz con la respuesta de JB Nizet (incluso si al final funciona).
Cuando acabo de hacer la relación ansiosa, JPA está examinando exactamente los mismos datos que cuando lo hago perezoso y agrego la cláusula fetch a Criteria/JPQL. Las relaciones entre los diversos elementos también son claras, ya que defino el ListAttribute
para la consulta Criteria.
¿Hay alguna explicación razonable por la razón de que JPA no devuelve los mismos datos en ambos casos?
ACTUALIZACIÓN DE GENEROSIDAD: Si bien la respuesta de JB Nizet ha solucionado el problema, todavía me resulta sin sentido que, dados dos operaciones con el mismo significado ("Obtener Ticket
a buscar todas WorkOrder
dentro ticket.workOrders
"), haciendo de ellos por una carga ansiosa no necesita más cambios mientras que especificar una búsqueda requiere un comando DISTINCT
Si nos fijamos en [combinación izquierda] (http://www.w3schools.com/sql/sql_join_left.asp), que es la forma en que funciona. ¿Por qué necesita obtener resultados por leftjoin? – JMelnik
De las tres opciones disponibles en la API de criterios, es la más sensata. Estamos hablando de JPA aquí, así que esperaba que la API organizara el SQL en las entidades de una manera más adecuada. – SJuan76
Ver mi respuesta editada. –