Tengo un insertOrUpdate
método que inserta un Entity
cuando no existe o lo actualizo si lo hace. Para habilitar esto, tengo que hacerlo findByIdAndForeignKey
, si devuelve null
insertar, si no, actualizar. El problema es cómo verifico si existe. Entonces lo intenté getSingleResult
. Pero arroja una excepción si el
public Profile findByUserNameAndPropertyName(String userName, String propertyName) {
String namedQuery = Profile.class.getSimpleName() + ".findByUserNameAndPropertyName";
Query query = entityManager.createNamedQuery(namedQuery);
query.setParameter("name", userName);
query.setParameter("propName", propertyName);
Object result = query.getSingleResult();
if (result == null) return null;
return (Profile) result;
}
pero getSingleResult
lanza un Exception
.
Gracias
getSingleResult()
se usa en situaciones como: " Estoy totalmente seguro de que este registro existe. Dispárame si no existe ". No quiero probarnull
cada vez que uso este método porque estoy seguro de que no lo devolverá. De lo contrario, causa una gran cantidad de programación repetitiva y defensiva. Y si el registro realmente no existe (a diferencia de lo que asumimos), es mucho mejor haberloNoResultException
comparado conNullPointerException
algunas líneas más adelante. Por supuesto, tener dos versiones degetSingleResult()
sería increíble, pero si tengo que elegir una ...Encapsulé la lógica en el siguiente método auxiliar.
fuente
Prueba esto en Java 8:
fuente
.orElse(null)
Aquí hay una buena opción para hacer esto:
fuente
TypedQuery<T>
embargo, aceptaría , en cuyo caso, elgetResultList()
ya está correctamente escrito como aList<T>
.fetch()
la entidad podría no estar completamente poblada. Ver stackoverflow.com/a/39235828/661414setMaxResults()
tiene una interfaz fluida para que pueda escribirquery.setMaxResults(1).getResultList().stream().findFirst().orElse(null)
. Este debería ser el esquema de llamadas más eficiente en Java 8+.Spring tiene un método de utilidad para esto:
fuente
He hecho (en Java 8):
fuente
Desde JPA 2.2 , en lugar de
.getResultList()
verificar si la lista está vacía o crear una secuencia, puede devolver la secuencia y tomar el primer elemento.fuente
Si desea utilizar el mecanismo try / catch para manejar este problema ... entonces puede usarse para actuar como si / si no. Utilicé try / catch para agregar un nuevo registro cuando no encontré uno existente.
fuente
Aquí hay una versión tipificada / genérica, basada en la implementación de Rodrigo IronMan:
fuente
Hay una alternativa que recomendaría:
Esta protección contra la excepción de puntero nulo garantiza que solo se devuelva 1 resultado.
fuente
¡Entonces no hagas eso!
Tienes dos opciones:
Ejecute una selección para obtener el CONTEO de su conjunto de resultados y solo extraiga los datos si este conteo no es cero; o
Use el otro tipo de consulta (que obtiene un conjunto de resultados) y verifique si tiene 0 o más resultados. Debería tener 1, así que retíralo de tu colección de resultados y listo.
Me gustaría ir con la segunda sugerencia, de acuerdo con Cletus. Ofrece un mejor rendimiento que (potencialmente) 2 consultas. También menos trabajo.
fuente
Combinando los bits útiles de las respuestas existentes (limitando el número de resultados, verificando que el resultado sea único) y usando el nombre del método estabilshed (Hibernate), obtenemos:
fuente
El método no documentado
uniqueResultOptional
en org.hibernate.query.Query debería hacer el truco. En lugar de tener que atrapar a unNoResultException
solo puede llamarquery.uniqueResultOptional().orElse(null)
.fuente
Resolví esto usando
List<?> myList = query.getResultList();
y comprobando simyList.size()
es igual a cero.fuente
Aquí está la misma lógica que otros sugirieron (obtenga la lista de resultados, devuelva su único elemento o nulo), utilizando Google Guava y TypedQuery.
Tenga en cuenta que Guava devolverá la IllegalArgumentException no intuitiva si el conjunto de resultados tiene más de un resultado. (La excepción tiene sentido para los clientes de getOnlyElement (), ya que toma la lista de resultados como argumento, pero es menos comprensible para los clientes de getSingleResultOrNull ()).
fuente
Aquí hay otra extensión, esta vez en Scala.
Con este chulo:
fuente
Mira este código:
return query.getResultList().stream().findFirst().orElse(null);
Cuando
findFirst()
se llama tal vez se puede lanzar una NullPointerException.El mejor enfoque es:
return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);
fuente
Por lo tanto, toda la solución "tratar de reescribir sin excepción" en esta página tiene un problema menor. O no arroja una excepción no única, ni la arroja en algunos casos incorrectos también (ver más abajo).
Creo que la solución adecuada es (tal vez) esto:
Se devuelve con nulo si hay 0 elementos en la lista, se devuelve no único si hay elementos diferentes en la lista, pero no se devuelve no único cuando uno de los seleccionados no está diseñado correctamente y devuelve el mismo objeto más de una vez.
Siéntase libre de comentar.
fuente
Lo logré obteniendo una lista de resultados y luego verificando si está vacía
Es tan molesto que
getSingleResult()
arroja excepcionesLanza
fuente
Eso me funciona:
fuente