Java JPA getSingleResult()或null
我有一个Java JPA getSingleResult()或null,java,jpa,Java,Jpa,我有一个insertOrUpdate方法,当实体不存在时插入一个实体,如果存在则更新它。要启用此功能,我必须findbyiandforeignkey,如果它返回null则插入,如果没有,则更新。问题是如何检查它是否存在?所以我尝试了getSingleResult。但是如果 public Profile findByUserNameAndPropertyName(String userName, String propertyName) { String namedQuery = Prof
insertOrUpdate
方法,当实体不存在时插入一个实体
,如果存在则更新它。要启用此功能,我必须findbyiandforeignkey
,如果它返回null
则插入,如果没有,则更新。问题是如何检查它是否存在?所以我尝试了getSingleResult
。但是如果
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;
}
但是getSingleResult
抛出一个异常
谢谢抛出异常表示找不到异常。我个人无法忍受这种API。它强制进行虚假的异常处理,而没有真正的好处。您只需将代码包装在try-catch块中
或者,您可以查询列表并查看其是否为空。这不会引发异常。实际上,由于您在技术上没有进行主键查找,因此可能会有多个结果(即使是一个结果、两个结果或外键或约束的组合在实践中不可能实现),因此这可能是更合适的解决方案。所以不要这样做
您有两个选择:
运行选择以获取结果集的计数,并且仅当该计数非零时才拉入数据;或
使用另一种查询(获取结果集)并检查它是否有0个或更多结果。它应该有1个,所以从结果集合中取出它,就完成了
我同意第二个建议,同意克莱特斯的意见。它提供了比(可能)2个查询更好的性能。也减少了工作量。我将逻辑封装在以下助手方法中
public class JpaResultHelper {
public static Object getSingleResultOrNull(Query query){
List results = query.getResultList();
if (results.isEmpty()) return null;
else if (results.size() == 1) return results.get(0);
throw new NonUniqueResultException();
}
}
使用Google Guava和TypedQuery,这里的逻辑与其他人建议的相同(获取resultList,返回其唯一元素或null)
public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
return Iterables.getOnlyElement(query.getResultList(), null);
}
公共静态getSingleResultOrNull(最终类型查询){
返回Iterables.getOnlyElement(query.getResultList(),null);
}
注意,如果结果集有多个结果,Guava将返回不直观的IllegalArgumentException。(该异常对于getOnlyElement()的客户端是有意义的,因为它将结果列表作为其参数,但对于getSingleResultOrNull()的客户端来说不太容易理解。)这里有一个很好的选项:
public static <T> T getSingleResult(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
publicstatict getSingleResult(TypedQuery查询){
query.setMaxResults(1);
List=query.getResultList();
if(list==null | | list.isEmpty()){
返回null;
}
返回列表。获取(0);
}
我推荐一种替代方案:
Query query = em.createQuery("your query");
List<Element> elementList = query.getResultList();
return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);
Query Query=em.createQuery(“您的查询”);
List elementList=query.getResultList();
返回CollectionUtils.isEmpty(元素列表)?null:elementList.get(0);
这可以防止空指针异常,保证只返回一个结果。这里是另一个扩展,这次是在Scala中
customerQuery.getSingleOrNone match {
case Some(c) => // ...
case None => // ...
}
这个皮条客:
import javax.persistence.{NonUniqueResultException, TypedQuery}
import scala.collection.JavaConversions._
object Implicits {
class RichTypedQuery[T](q: TypedQuery[T]) {
def getSingleOrNone : Option[T] = {
val results = q.setMaxResults(2).getResultList
if (results.isEmpty)
None
else if (results.size == 1)
Some(results.head)
else
throw new NonUniqueResultException()
}
}
implicit def query2RichQuery[T](q: TypedQuery[T]) = new RichTypedQuery[T](q)
}
如果您希望使用try/catch机制来处理此问题。。然后,它可以像if/else一样使用。我使用try/catch在找不到现有记录时添加新记录
try { //if part
record = query.getSingleResult();
//use the record from the fetched result.
}
catch(NoResultException e){ //else part
//create a new record.
record = new Record();
//.........
entityManager.persist(record);
}
以下是基于Rodrigo IronMan实现的类型化/泛型版本:
public static <T> T getSingleResultOrNull(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
public static T getSingleResultOrNull(TypedQuery查询){
query.setMaxResults(1);
List=query.getResultList();
if(list.isEmpty()){
返回null;
}
返回列表。获取(0);
}
Spring为此提供了:
TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class);
...
return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
TypedQuery query=em.createNamedQuery(namedQuery,Profile.class);
...
返回org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
因此,本页中所有的“尝试无例外地重写”解决方案都有一个小问题。要么它不会抛出非唯一异常,要么在某些错误情况下也不会抛出它(见下文)
我认为正确的解决办法是(也许)这样:
public static L getSingleResultOrNull(TypedQuery){
List results=query.getResultList();
L foundEntity=null;
如果(!results.isEmpty()){
foundEntity=results.get(0);
}
如果(results.size()>1){
对于(L结果:结果){
如果(结果!=foundEntity){
抛出新的ununiqueresultexception();
}
}
}
返回实体;
}
如果列表中有0个元素,则返回null;如果列表中有不同的元素,则返回ununique;但如果选择的一个元素设计不正确,则不返回ununique,并多次返回同一对象
请随意评论。结合现有答案的有用部分(限制结果数量,检查结果是否唯一)并使用已建立的方法名称(Hibernate),我们得到:
/**
*返回与查询匹配的单个实例,如果查询未返回任何结果,则返回null。
*
*@param查询(必需)
*@param结果记录类型
*@返回记录或空
*/
公共静态T uniqueResult(@NotNull TypedQuery查询){
List results=query.setMaxResults(2.getResultList();
如果(results.size()>1)抛出新的ununiquereSultException();
返回results.isEmpty()?null:results.get(0);
}
在Java 8中尝试以下操作:
Optional first = query.getResultList().stream().findFirst();
query.getResultList().stream().findFirst().orElse(null);
org.hibernate.query.query中未记录的方法uniquerysultoptional
,应该可以做到这一点。您不必捕获NoResultException
,只需调用query.uniqueResultOptional().orElse(null)
即可(在Java 8中):
我通过使用List myList=query.getResultList()解决了这个问题
并检查myList.size()是否等于零。这对我来说很有用:
Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;
Optional opt=Optional.ofNullable(nativeQuery.getSingleResult());
返回opt.isPresent()?opt.get():null;
查看以下代码:
返回query.getResultList().stream().findFirst().orElse(null)代码>
调用findFirst()
时,可能会抛出NullPointerException
我最喜欢的一条裙子
query.getResultList().stream().findFirst().orElse(null);
Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;
public boolean exist(String value) {
List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
return !options.isEmpty();
}
.getResultStream()
.findFirst()
.orElse(null);