Criterios de API: recuperación de una lista devuelve repetido principal de la entidad

Tengo las siguientes Entidades; Entrada contiene un conjunto de 0,N orden de trabajo:

@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 carga de los Boletos y la captura de los atributos. Todos los 0,1 atributos no presentan ningún problema. Por órdenes de trabajo, he utilizado esta respuesta para obtener el código siguiente.

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 debe volver a mí 1 Billete de 5 órdenes de trabajo, estoy recuperando el mismo Billete de 5 veces.

Si acabo de hacer las órdenes de trabajo de un Deseosos de Capturar y eliminar la captura de código, funciona como debería.

Alguien me puede ayudar? Gracias de antemano.

ACTUALIZACIÓN:

Una explicación acerca de por qué no soy feliz con JB Nizet la respuesta (incluso si al final no funciona).

Cuando acabo de hacer la relación con ganas, JPA es el examen de exactamente los mismos datos que cuando me hacen perezosos y agregar la cláusula fetch a los Criterios /JPQL. Las relaciones entre los distintos elementos que también está claro, como defino el ListAttribute para los Criterios de la consulta.

Hay algunos razonable explanaition por la razón de que JPA no devolución de los mismos datos en ambos casos?

ACTUALIZACIÓN DE RECOMPENSA: Mientras JB Nizet la respuesta me resuelve el problema, creo que es de sentido que, dados dos operaciones con el mismo significado («Get Ticket y traer todos los WorkOrder dentro de ticket.workOrders«), haciendo de ellos por una con ganas de carga no necesita cambios, mientras que la especificación de una recuperación requiere un DISTINCT comando

Si usted mira en Left Join, es la forma en que funciona. Por qué usted necesita para obtener los resultados por leftjoin?
De las tres opciones disponibles en la API de criterios, es la más sensata. Estamos hablando de JPA aquí, así que me esperaba una API para organizar el SQL en las entidades en una más manera adecuada.
Ver editado mi respuesta.

OriginalEl autor SJuan76 | 2012-06-14

2 Kommentare

  1. 23
    1. Hay una diferencia entre con ganas de carga y captura de combinación. Con ganas de carga no significa que los datos se cargan dentro de la misma consulta. Simplemente significa que se carga de inmediato, aunque por consultas adicionales.

    2. Los criterios siempre se traduce a una consulta SQL. Si usted especificar las combinaciones, será participar en SQL. Por la naturaleza de SQL, esto multiplica los datos de la entidad raíz, lo que lleva a que el efecto que tiene. (Tenga en cuenta que usted consigue la misma instancia varias veces, así que la raíz de la entidad, no se multiplica en la memoria.)

    Existen varias soluciones para que:

    • uso distinct(true)
    • El uso de los distintos entidad raíz del transformador (.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)).
    • Cuando usted no necesita filtro por niño propiedades, evitar la combinación
    • Cuando usted necesita el filtro por niño propiedades, filtrar por una subconsulta (DetachedCriteria).
    • Optimizar el N+1 problema mediante el uso de lote de tamaño

    OriginalEl autor Stefan Steinegger

  2. 4

    Ha intentado llamar distinct(true) en el CriteriaQuery?

    La JPA 2 de la especificación, página 161, dice:

    La palabra clave DISTINCT se utiliza para especificar que los valores duplicados deben ser
    eliminado de los resultados de la consulta.

    DISTINTO si no se especifica, los valores duplicados no son eliminados.

    El javadoc también dice:

    Especificar si duplicar los resultados de la consulta serán eliminados.Un verdadero
    valor hará que duplica a ser eliminado. Un valor falso hará que
    duplicados se conservan. Si distintos no se ha especificado,
    duplicar los resultados deben conservarse.

    La razón por la que usted no necesita los distintos cuando la asociación es muy cargado es, probablemente, sólo que la asociación no se ha cargado mediante una captura de unirse, pero el uso de una consulta adicional.

    Ok, con distinct(true) funciona. Pero, ¿es la solución «correcta» o simplemente una solución? Me parece ilógico que yo estoy diciendo JPA que estoy buscando Ticket y que las órdenes de trabajo debe ser cargado en una Lista, y que JPA devuelve me el producto cartesiano.
    Supongo que esta es la solución correcta, porque eso es lo que la palabra clave distinct también en JPQL (o, al menos, en HQL).
    El único problema con distrinct(true) se estropea con su OrderBy si se basan en atributo de un atributo.

    OriginalEl autor JB Nizet

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea