2011-07-18 25 views
7

No sé cómo hacer que la consulta de criterios JAP termine con un resultado booleano.¿Cómo determinar correctamente si una cláusula de consulta de criterios JPA "existente" devuelve verdadero o falso?

El objetivo es tener una consulta criterios que tiene este aspecto cuando se representa en Oracle:

select 1 from dual where exists (...); 

El where exists (...) parte que hice con una subconsulta, estoy luchando con la consulta externa.

Y el uso práctico de esto es determinar si esa subconsulta en la cláusula exists devolvió true o false.

Esto es lo que tengo:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 

CriteriaQuery<Object> query = criteriaBuilder.createQuery(); 
query.from(Boolean.class); 
query.select(criteriaBuilder.literal(true)); 

Subquery<Location> subquery = query.subquery(Location.class); 
Root<Location> subRootEntity = subquery.from(Location.class); 
subquery.select(subRootEntity); 

Path<?> attributePath = subRootEntity.get("State"); 
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX")); 
subquery.where(predicate); 
query.where(criteriaBuilder.exists(subquery)); 

TypedQuery<Object> typedQuery = em.createQuery(query); 

Pero la última línea de falla diciendo booleana no es una entidad. Creo que no se sabe cómo expresar la parte "de" de la consulta porque el resultado sería 1 o 0, verdadero o falso, y no una entidad.

Sé que podría recuperar cualquier entidad y luego verificar si la lista de resultados tiene el tamaño 1, pero estoy tratando de aprender cómo obtener un resultado booleano para evitar la tarea innecesaria de recuperar esas columnas y también para aprender cómo hacerlo.

¿Es esto posible en absoluto?

Gracias! Eduardo

+2

No, no lo puede hacer directamente, sino que es una forma común para comprobar si la cuenta de resultado es decir establecer si el recuento es mayor que cero, entonces la verdadera cosa falsa. – Shahzeb

Respuesta

6

Se podría hacer una selección para una propiedad (por ejemplo, el ID) y establecer los resultados max volvieron a 1, de modo que se asegure el PP no hace más trabajo de lo necesario (como contar todos los casos). Entonces su lista de resultados estará vacía (existe = falso) o tiene un elemento (existe = verdadero).

+0

Esto es lo que estaba buscando, una forma de lograrlo sin tener el DBMS trabajando más de lo necesario. ¡¡Gracias!! –

0

Creo que el problema es la query.from (Boolean.class). Intenta crear una consulta "select object from boolean". Si quieres un booleano como tipo de retorno es necesario utilizar

CriteriaQuery<Boolean> query = criteriaBuilder.createQuery(Boolean.class) 

Entonces consultar desde cualquier tabla de entidad existente para crear una consulta válida (tal vez de la mesa de la subconsulta). No creo que cree a partir de trabajos duales, excepto si logró asignar la tabla dual.

-2

¿Hay alguna razón para que toda la lógica tenga que estar en JPA? Si no, ¿por qué no utilizar SELECT COUNT y luego un condicional para establecer el booleano?

Boolean exists = false; 
int count = selectCountQuery(); 
if (count > 0) { 
    exists = true; 
} 
10

Sí, esto es posible. Suponiendo que tiene una entidad correspondiente a su tabla dual, querrá usar esa clase de entidad en CriteriaQuery#from.

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 

CriteriaQuery<Boolean> query = criteriaBuilder.createQuery(Boolean.class); 
query.from(dual.class); 
query.select(criteriaBuilder.literal(true)); 

Subquery<Location> subquery = query.subquery(Location.class); 
Root<Location> subRootEntity = subquery.from(Location.class); 
subquery.select(subRootEntity); 

Path<?> attributePath = subRootEntity.get("State"); 
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX")); 
subquery.where(predicate); 
query.where(criteriaBuilder.exists(subquery)); 

TypedQuery<Boolean> typedQuery = em.createQuery(query); 
2

Sé que esto es una cuestión mayor, pero para una persona que quiere: ¿Qué hay de tratar de usar la anotación JPA @Query de primavera y una consulta SELECT CASE (dependiendo de su aplicación db) con un método que devuelve un valor lógico . Por ejemplo (MySQL):

@Query("SELECT CASE WHEN COUNT(l) > 0 THEN TRUE ELSE FALSE END FROM Location l WHERE l.state=?1") 
boolean locationForStateExists(String state); 

A veces, sólo mediante la cadena de consulta en @Query puede ser un salvavidas cuando el generador de consultas métodos JPA o llamado no llegan a hacer lo que desea.

+0

Esto se basa en 'count()', que es el problema fundamental. Hibernate no es compatible con la palabra clave 'exists', excepto dentro de la cláusula' where', que no cumple con lo que el OP está pidiendo. Seleccionar un 'conteo 'podría ser extremadamente lento (dependiendo de la complejidad de la cláusula' where', presencia de índices, etc.) mientras que una cláusula 'exists' fallará rápidamente en la primera aparición. Es realmente una pena que JPA/Hibernate no sea compatible con esta optimización trivial. –

1

Hibernate 5 está funcionando:

Subquery<Integer> subquery = query.subquery(Integer.class); 
Root<Location> subRootEntity = subquery.from(Location.class); 
subquery.select(criteriaBuilder.literal(1)); 

Path<?> attributePath = subRootEntity.get("State"); 
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX")); 
subquery.where(predicate); 
query.where(criteriaBuilder.exists(subquery)); 
+0

¡Gracias por la actualización! –

Cuestiones relacionadas