2010-12-07 20 views
18

Deseo saber si un registro dado está presente en una base de datos o no. Hasta ahora lo he logrado escribiendo una consulta JPA y ejecutándola por el método getSingleResult(). esto lanzaría un NoResultException si el registro con el parámetro dado no existe. Por supuesto, no es imprescindible que exista el registro, por lo que a veces es el comportamiento normal, es por eso que me pregunté a mí mismo si es necesario lanzar una Excepción que tengo que manejar con un bloque catch. Por lo que sé, el costo del manejo de excepciones es bastante grande, así que no estoy muy satisfecho con esta solución, además, ni siquiera necesito el objeto, solo necesito saber su existencia en la base de datos.Cómo verificar si existe un registro usando JPA

¿Existe alguna forma mejor de verificar si un objeto existe o no? p.ej. usando getResultList() y verificando su tamaño tal vez?

+1

Buena pregunta, pero se debe cambiar el título de "¿Cómo comprobar si existe un registro utilizando JPA" o algo similar. –

+0

gracias por la observación, hecho :) –

+0

actualización: método repository exist (id). repo.exist (id) devuelve true si existe el registro o si es falso –

Respuesta

20

Si solo desea saber si el objeto existe, envíe un SELECT COUNT a su base de datos. Eso devolverá 0 o 1.

El costo del manejo de excepciones no es tan grande (a menos que lo haga millones de veces durante una operación normal), así que no me molestaría.

Pero el código realmente no refleja su intención. Desde getSingleResult() llama getResultList() internamente, es más claro de este modo:

public boolean objExists(...) { 
    return getResultList(...).size() == 1; 
} 

si se consulta por objeto Identificación y ha habilitado el almacenamiento en caché, que se convertirá en una simple búsqueda en la caché si el objeto ya se ha cargado.

+0

oh, tiene toda la razón sobre la solución SELECT COUNT, por algún motivo la ignoré. pero la segunda parte de tu respuesta contiene la información que realmente necesitaba y muchas gracias por eso. –

+0

¿Está de acuerdo con que si quiere obtener el primer resultado de la consulta, y es habitual que la consulta no devuelva nada, es mejor hacer 'query.setMaxResults (1)' y luego 'getResultList()'? De esta manera, evitaríamos manejar la excepción. (NOTA: estoy ejecutando esto en un trabajo que se llama MUCHAS veces). – GuilhermeA

+0

@GuilhermeA: hay demasiadas variables para decir con certeza.Cosas que afectan el rendimiento: controlador JDBC, soporte para el DB en su asignador OR (¿cómo implementan 'setMaxResults()' en el nivel SQL?), Tamaño de la tabla, la consulta misma, etc. Ejecute un par de pruebas de rendimiento para descubrir. –

5

Si está buscando por clave principal también puede usar Entitymanger.find(entityClass, primaryKey) que devuelve null cuando la entidad no existe.

+3

Si la entidad existe, se cargará en la sesión, solo para dejarla allí. – Radu

+0

@Radu Ha pasado un tiempo desde que trabajé con jpa, pero el mismo problema se aplicaría a las soluciones que usan 'getResultList', ¿verdad? –

+1

Sí, considerando 'getSingleResult()' también funciona con una lista de resultados internamente. Pero lo que necesitamos aquí es verificar la existencia de una entidad, sin la posible sobrecarga de cargarla en la sesión. Una operación de recuento siempre devolverá un número, por lo que incluso evitamos la excepción NoResultException. – Radu

10

Trate de evitar cargar la entidad en la sesión (getSingleResult()) solo para comprobar su existencia. Un conteo es mejor aquí. Con la API de criterios de consulta se vería algo como esto:

public <E extends AbstractEntity> boolean exists(final Class<E> entityClass, final int id) { 
    final EntityManager em = getEntityManager(); 
    final CriteriaBuilder cb = em.getCriteriaBuilder(); 

    final CriteriaQuery<Long> cq = cb.createQuery(Long.class); 
    final Root<E> from = cq.from(entityClass); 

    cq.select(cb.count(from)); 
    cq.where(cb.equal(from.get(AbstractEntity_.id), id)); 

    final TypedQuery<Long> tq = em.createQuery(cq); 
    return tq.getSingleResult() > 0; 
} 
+0

¿de qué clase se está extendiendo en su ejemplo? No pude encontrar ningún método 'exists' existente en ninguna parte. – Anticom

+0

No encontrará este método en ninguna parte de las bibliotecas JPA. Debe implementarlo en algún lugar de su código y usar las API de JPA. – Radu

+0

¿Por qué hay una anotación '@ Override' entonces? Eso es lo que me confundió;) – Anticom

1

Utilice simplemente count(e) en la consulta, por lo que no NoResultException serán arrojados, y evitará la carga del objeto entidad
Así que el código Java puede ser tan siga :

public boolean isRecordExist() { 
    String query = "select count(e) from YOUR_ENTITY e where ...."; 
    // you will always get a single result 
    Long count = (Long) entityManager.createQuery(query).getSingleResult(); 
    return ((count.equals(0L)) ? false : true); 
} 

la esperanza de que ayude a alguien :)

+0

Ayudó a tener un ejemplo de código – keiki

0

aquí es un enfoque genérico para trabajar con un tipo T y un arbitraria ID valor

public boolean exists(Object key) { 
    EntityManager entityManager = getEntityManager(); 
    Metamodel metamodel = entityManager.getMetamodel(); 
    EntityType<T> entity = metamodel.entity(entityClass); 
    SingularAttribute<T, ? extends Object> declaredId = entity.getDeclaredId(key.getClass()); 
    CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
    javax.persistence.criteria.CriteriaQuery<T> cq = cb.createQuery(entityClass); 
    Root<T> from = cq.from(entityClass); 
    Predicate condition = cb.equal(from.get(declaredId), key); 
    cq.where(condition); 
    TypedQuery<T> q = entityManager.createQuery(cq); 
    return q.getResultList().size() > 0; 
} 
Cuestiones relacionadas