java - consultas - API de JPA y criterios: seleccione solo columnas específicas
consultas jpa java (3)
Me gustaría seleccionar solo columnas específicas (por ejemplo, SELECT a FROM b
). Tengo un DAO genérico y lo que se me ocurre es:
public List<T> getAll(boolean idAndVersionOnly) {
CriteriaBuilder builder = manager.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(entityClazz);
Root<T> root = criteria.from(entityClazz);
if (idAndVersionOnly) {
criteria.select(root.get("ID").get("VERSION")); // HERE IS ERROR
} else {
criteria.select(root);
}
return manager.createQuery(criteria).getResultList();
}
Y el error es: The method select(Selection<? extends T>) in the type CriteriaQuery<T> is not applicable for the arguments (Path<Object>)
. ¿Cómo debería cambiar eso? Quiero obtener un objeto tipo T
que solo tenga campos ID
y VERSION
, y todos los demás son null
.
Tipo T
extiende AbstractEntity
que tiene esos 2 campos.
entityClazz
es T.class
.
Antes que nada, realmente no veo por qué querrías que un objeto solo tenga ID y Versión, y todos los demás accesorios sean nulos. Sin embargo, aquí hay un código que lo hará por usted (que no utiliza JPA Em, pero Hibernate normal. Supongo que puede encontrar la equivalencia en JPA o simplemente obtener el obj de sesión de Hibernate del delegado em Acceso a la sesión de Hibernate de EJB utilizando EntityManager ):
List<T> results = session.createCriteria(entityClazz)
.setProjection( Projections.projectionList()
.add( Property.forName("ID") )
.add( Property.forName("VERSION") )
)
.setResultTransformer(Transformers.aliasToBean(entityClazz);
.list();
Esto devolverá una lista de Objetos que tengan su ID y conjunto de Versión y todos los demás accesorios a nulo, ya que el transformador aliasToBean no podrá encontrarlos. De nuevo, estoy seguro de que puedo pensar en una situación en la que me gustaría hacer eso.
Una de las formas de JPA para obtener solo columnas particulares es pedir un objeto Tuple .
En tu caso, necesitarías escribir algo como esto:
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
// write the Root, Path elements as usual
Root<EntityClazz> root = cq.from(EntityClazz.class);
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION)); //using metamodel
List<Tuple> tupleResult = em.createQuery(cq).getResultList();
for (Tuple t : tupleResult) {
Long id = (Long) t.get(0);
Long version = (Long) t.get(1);
}
Otro enfoque es posible si tiene una clase que representa el resultado, como T
en su caso. T
no necesita ser una clase de Entidad. Si T
tiene un constructor como:
public T(Long id, Long version)
entonces puedes usar T
directamente en tu constructor de CriteriaQuery
:
CriteriaQuery<T> cq = builder.createQuery(T.class);
// write the Root, Path elements as usual
Root<EntityClazz> root = cq.from(EntityClazz.class);
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION)); //using metamodel
List<T> result = em.createQuery(cq).getResultList();
Vea este link para más referencia.
cq.select(cb.construct(entityClazz.class, root.get("ID"), root.get("VERSION"))); // HERE IS NO ERROR