java - example - jpa query
API de criterios de JPA: cómo agregar la cláusula JOIN(como oración general posible) (4)
¡Advertencia! Hay un número de errores en el ejemplo de Sun JPA 2 y el contenido pegado resultante en la respuesta de Pascal. Por favor consulte esta publicación .
Esta publicación y el ejemplo de Sun Java EE 6 JPA 2 realmente impidieron mi comprensión de JPA 2. Después de repasar los manuales de Hibernate y OpenJPA y pensando que tenía una buena comprensión de JPA 2, aún así me confundí cuando volví a esta publicación. .
Estoy tratando de construir consultas dinámicamente, y mi próximo objetivo es agregar cláusulas JOIN (no sé cómo puedo usar la API).
Por ahora, por ejemplo, este código funciona para mí:
...
Class baseClass;
...
CriteriaBuilder cb = JpaHandle.get().getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(this.baseClass);
Root entity_ = cq.from(this.baseClass);
Predicate restrictions = null;
...
restrictions = cb.conjunction();
restrictions = cb.and(restrictions, entity_.get("id").in(this.listId));
...
cq.where(restrictions);
...
Query qry = JpaHandle.get().createQuery(cq);
(Nota: JpaHandle es de la implementación wicket-JPA)
Mi deseo es agregar cláusula JOIN (lo más genérico posible).
Tengo las anotaciones particulares en las clases (this.baseClass)
Por ejemplo :
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "assay_id", nullable = false)
Entonces, ¿hay alguna forma de algo así en JPA estándar? (Nota: esto no compila)
Aquí falla un enfoque práctico:
...
Join<Experiment,Assay> experimentAssays = entity_.join( entity_.get("assay_id") );
O así:
...
CriteriaQuery<Customer> q = cb.createQuery(Customer.class);
Root<Customer> c = q.from(Customer.class);
SetJoin<Customer, PurchaseOrder> o = c.join(Customer_.orders);
Para mí, si pudiera ser lo más genérico posible, sería genial ...
...
Join joinClause = entity_join(entity_.get("assay_id"), entity2_.get("id"));
Por supuesto, tengo las anotaciones particulares en las clases (this.baseClass)
Gracias por tu tiempo. ¡Agradeceré todo tipo de comentarios!
En realidad, no tiene que lidiar con el metamodelo estático si tiene sus anotaciones correctas.
Puedes usar esto:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> petMetaModel = m.entity(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(petMetaModel.getSet("owners", Owner.class));
No necesita aprender JPA. Puede usar mis criterios fáciles para JPA2 ( https://sourceforge.net/projects/easy-criteria/files/ ). Aquí está el ejemplo
CriteriaComposer<Pet> petCriteria CriteriaComposer.from(Pet.class).
where(Pet_.type, EQUAL, "Cat").join(Pet_.owner).where(Ower_.name,EQUAL, "foo");
List<Pet> result = CriteriaProcessor.findAllEntiry(petCriteria);
O
List<Tuple> result = CriteriaProcessor.findAllTuple(petCriteria);
Tal vez el siguiente extracto del capítulo 23 - Uso de la API Criteria para crear consultas del tutorial Java EE 6 arroje algo de luz (de hecho, sugiero leer todo el Capítulo 23):
Consultando relaciones usando combinaciones
Para las consultas que navegan a clases de entidad relacionadas, la consulta debe definir una unión a la entidad relacionada llamando a uno de los métodos
From.join
en el objeto raíz de consulta u otro objeto dejoin
. Los métodos de unión son similares a la palabra claveJOIN
en JPQL.El objetivo de la combinación utiliza la clase Metamodel del tipo
EntityType<T>
para especificar el campo o la propiedad persistente de la entidad unida.Los métodos join devuelven un objeto de tipo
Join<X, Y>
, dondeX
es la entidad fuente eY
es el objetivo de la unión.Ejemplo 23-10 Unirse a una consulta
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class); Metamodel m = em.getMetamodel(); EntityType<Pet> Pet_ = m.entity(Pet.class); Root<Pet> pet = cq.from(Pet.class); Join<Pet, Owner> owner = pet.join(Pet_.owners);
Las uniones se pueden encadenar juntas para navegar a entidades relacionadas de la entidad objetivo sin tener que crear una instancia de
Join<X, Y>
Unir para cada unión.Ejemplo 23-11 Encadenamiento de uniones en una consulta
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class); Metamodel m = em.getMetamodel(); EntityType<Pet> Pet_ = m.entity(Pet.class); EntityType<Owner> Owner_ = m.entity(Owner.class); Root<Pet> pet = cq.from(Pet.class); Join<Owner, Address> address = cq.join(Pet_.owners).join(Owner_.addresses);
Dicho esto, tengo algunos comentarios adicionales:
Primero, la siguiente línea en tu código:
Root entity_ = cq.from(this.baseClass);
Me hace pensar que de alguna manera te perdiste la parte de Static Metamodel Classes. Las clases de metamodelos, como Pet_
en el ejemplo citado, se usan para describir la metainformación de una clase persistente. Normalmente se generan utilizando un procesador de anotación ( clases de metamodelos canónicos ) o el desarrollador puede escribirlos ( metamodelo no canónico ). Pero tu sintaxis se ve rara, creo que intentas imitar algo que te perdiste.
En segundo lugar, realmente creo que debes olvidar esta clave extranjera assay_id
, estás en el camino equivocado aquí. Realmente necesita comenzar a pensar en objeto y asociación, no en tablas y columnas.
En tercer lugar, no estoy seguro de entender exactamente lo que quiere decir al agregar una cláusula JOIN tan genérica como sea posible y cómo se ve su modelo de objeto, ya que no lo proporcionó (vea el punto anterior). Por lo tanto, es imposible responder a su pregunta de manera más precisa.
En resumen, creo que debes leer un poco más acerca de los Criterios JPA 2.0 y la API Metamodel y recomiendo encarecidamente los siguientes recursos como punto de partida.
Ver también
- la sección 6.2.1 Clases de metamodelos estáticos en la especificación JPA 2.0
- Consultas dinámicas y seguras en JPA 2.0
- Uso de la API de criterios y Metamodel API para crear consultas básicas de tipo seguro