Este es realmente el comportamiento esperado si entendí su configuración correctamente.
Hibernate no devuelve resultados distintos para una consulta con la búsqueda de combinación externa habilitada para una colección (incluso si uso la palabra clave distinta). Primero, debe comprender SQL y cómo funcionan las OUTER JOIN en SQL. Si no comprende y comprende completamente las combinaciones externas en SQL, no continúe leyendo este artículo de preguntas frecuentes, pero consulte un manual o tutorial de SQL. De lo contrario, no comprenderá la siguiente explicación y se quejará de este comportamiento en el foro de Hibernate.
Ejemplos típicos que pueden devolver referencias duplicadas del mismo objeto Order:
List result = session.createCriteria(Order.class)
.setFetchMode("lineItems", FetchMode.JOIN)
.list();
<class name="Order">
...
<set name="lineItems" fetch="join">
List result = session.createCriteria(Order.class)
.list();
List result = session.createQuery("select o from Order o left join fetch o.lineItems").list();
Todos estos ejemplos producen la misma declaración SQL:
SELECT o.*, l.* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID
¿Quieres saber por qué hay duplicados? Mire el conjunto de resultados de SQL, Hibernate no oculta estos duplicados en el lado izquierdo del resultado combinado externo, pero devuelve todos los duplicados de la tabla inicial. Si tiene 5 pedidos en la base de datos y cada pedido tiene 3 elementos de línea, el conjunto de resultados será de 15 filas. La lista de resultados de Java de estas consultas tendrá 15 elementos, todos de tipo Order. Hibernate solo creará 5 instancias de Order, pero los duplicados del conjunto de resultados de SQL se conservan como referencias duplicadas a estas 5 instancias. Si no comprende esta última oración, debe leer sobre Java y la diferencia entre una instancia en el montón de Java y una referencia a dicha instancia.
(¿Por qué una combinación externa a la izquierda? Si tuviera un pedido adicional sin líneas de pedido, el conjunto de resultados sería 16 filas con NULL llenando el lado derecho, donde los datos de la línea de pedido son para otro pedido. Desea pedidos incluso si no tienen líneas de pedido, ¿verdad? De lo contrario, utilice una búsqueda de combinación interna en su HQL).
Hibernate no filtra estas referencias duplicadas de forma predeterminada. Algunas personas (no tú) realmente quieren esto. ¿Cómo puedes filtrarlos?
Me gusta esto:
Collection result = new LinkedHashSet( session.create*(...).list() );