update query parameter example ejemplos ejemplo jpa jpa-2.0 criteria-api

jpa - query - ¿Cómo hacer que un CriteriaBuilder se una con una condición de "encendido" personalizado?



jpa criteria update example (5)

Creo que este es el mismo problema que se plantea en esta pregunta. Parece que no es posible en CriteriaBuilder. Es posible en la API de criterios de hibernación, pero eso probablemente no lo ayudará.

JPA Criteria API: condición múltiple en LEFT JOIN

Quiero hacer una consulta donde me uno a 2 tablas, utilizando el CriteriaBuilder. En MySQL la consulta que estoy tratando de hacer se vería así:

SELECT * FROM order LEFT JOIN item ON order.id = item.order_id AND item.type_id = 1

Quiero recibir todas las órdenes y si tienen un artículo del tipo # 1, quiero unirme a este artículo. Sin embargo, si no se encuentra ningún artículo del tipo # 1, todavía quiero obtener el pedido. No puedo averiguar cómo hacer esto con el CriteriaBuilder. Todo lo que sé hacer es:

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Order> cq = cb.createQuery(Order.class); Root<Order> order = cq.from(Order.class); Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT); Join<Item, Type> type = order.join(Item_.type, JoinType.LEFT); cq.select(order); cq.where(cb.equal(type.get(Type_.id), 1));

Esta consulta está rota, ya que resulta en algo como esto en MySQL:

SELECT * FROM order LEFT JOIN item ON order.id = item.order_id WHERE item.type_id = 1

El resultado solo contendrá pedidos con artículos del tipo # 1. Los pedidos sin están excluidos. ¿Cómo puedo usar el CriteriaBuilder para crear una consulta como en el primer ejemplo?


Es posible hacerlo utilizando el método on Join<Z, X> on(Predicate... restrictions);

Root<Order> order = cq.from(Order.class); Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT); item.on(cb.equal(item.get(Item_.type), 1));


Hay una solución alternativa si está utilizando Hibernate 3.6 con JPA 2.0. No es la mejor solución, sin embargo, funciona perfectamente para mí.

Dupliqué la entidad con la anotación de hibernación @Where. Esto significa que cada vez que use la unión con esta entidad, hibernará agregará la condición adicional a la declaración de unión en el SQL generado.

Por ejemplo, inicialmente tenemos el siguiente ejemplo:

@Entity @Table(name = "PERSON") public class Person { @Id @Column(name = "PERSON_ID") private Long id; @Id @Column(name = "PERSON_NAME") private String name; @OneToMany(mappedBy = "person", fetch = FetchType.LAZY) private Set<Address> addresses; } @Entity @Table(name = "ADDRESS") public class Address { @Id @Column(name = "ADDRESS_ID") private Long id; @Id @Column(name = "ADDRESS_STREET") private String street; @ManyToOne @JoinColumn(name = "PERSON_ID") private Person person; }

Para agregar condiciones adicionales en los criterios de unión, necesitamos duplicar el mapeo Address @Entity, agregando la anotación @Where @Where (cláusula = "ADDRESS_TYPE_ID = 2").

@Entity @Table(name = "ADDRESS") @Where(clause = " ADDRESS_TYPE_ID = 2") public class ShippingAddress { @Id @Column(name = "ADDRESS_ID") private Long id; @Id @Column(name = "ADDRESS_STREET") private String street; @OneToOne @JoinColumn(name = "PERSON_ID") private Person person; }

Además, debemos agregar la asociación de mapeo duplicada para la nueva entidad.

@Entity @Table(name = "PERSON") public class Person { @Id @Column(name = "PERSON_ID") private Long id; @Id @Column(name = "PERSON_NAME") private String name; @OneToMany(mappedBy = "person", fetch = FetchType.LAZY) private Set<Address> addresses; @OneToOne(mappedBy = "person") private ShippingAddress shippingAddress; }

Finalmente, puede utilizar una unión con esta entidad específica en sus criterios:

PersonRoot.join(Person_.shippingAddress, JoinType.LEFT);

El Hibernate Snippet SQL debería verse así:

left outer join address shippingadd13_ on person11_.person_id=shippingadd13_.person_id and ( shippingadd13_.ADDRESS_TYPE_ID = 2 )


La cláusula ON es compatible con la versión Hibernate 4.3, cualquiera sabe si existe un problema de indexación de parámetros entre el índice de parámetros de las condiciones personalizadas adicionales con el índice de los filtros de mapeo existentes al realizar una unión externa con la cláusula ON.

Usando la clase de entidad Persona a continuación como ejemplo, digamos que estoy agregando este filtro para limitar los tipos de direcciones y el filtro está habilitado para rellenar la cláusula IN. El índice de parámetros para la cláusula IN causará el problema [2] cuando agrego condiciones adicionales (como el uso de la columna ''calle'') parte de la cláusula ON. ¿Es un problema conocido?

[1] @Filter (name = "addressTypes", condition = "ADDRESS_TYPE in (: supportedTypes)")

[2] Causado por: ERROR 22018: Formato de cadena de caracteres no válido para el tipo BIGINT. Establecer direcciones privadas;


Sé que esta pregunta se hizo hace mucho tiempo, pero recientemente tuve el mismo problema y encontré esta solución en un foro de Oracle, la copié y pegué en caso de que el enlace ya no esté disponible.

MiguelChillitupaArmijos 29-abr-2011 1:41 (en respuesta a 840578) Piensa que deberías usar algo como:

em.createQuery("SELECT DISTINCT e.Id" + " from Email e " + " left join e.idEmailIn e2 *with* e2.responseType = ''response''" + " where e.type = ''in'' and e.responseMandatory = true").getSingleResult();

Y este es el enlace.

Criterios de JPA: UNIRSE IZQUIERDO con una condición AND