我有一个insertOrUpdate
方法,当Entity
不存在时插入findByIdAndForeignKey
,如果有,则更新它。要启用此功能,我必须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
但是Exception
会引发{{1}}。
由于
答案 0 :(得分:235)
抛出异常是getSingleResult()
表示无法找到的异常。我个人无法忍受这种API。它强制虚假的异常处理没有真正的好处。您只需将代码包装在try-catch块中即可。
或者,您可以查询列表并查看其是否为空。这不会引发异常。实际上,因为你没有在技术上进行主键查找,所以可能有多个结果(即使一个,两个或外键或约束的组合使得这在实践中不可能),所以这可能是更合适的解决方案。
答案 1 :(得分:31)
我在下面的帮助方法中封装了逻辑。
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();
}
}
答案 2 :(得分:22)
这是一个很好的选择:
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);
}
答案 3 :(得分:16)
在Java 8中试试这个:
Optional first = query.getResultList().stream().findFirst();
答案 4 :(得分:14)
Spring为此a utility method:
TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class);
...
return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
答案 5 :(得分:7)
如果您希望使用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);
}
答案 6 :(得分:6)
我已经完成了(在Java 8中):
@Override
public void onResponse(VolleyResponseBean response) {
if (response.isValidateWebServiceType(response)) {
switch (response.getWebServiceType()) {
case GET_LATEST_POST:
ArrayList<LatestPost> resposneObject = (ArrayList<LatestPost>) (ArrayList<?>)response.getWordPressDataList();
LogUtils.LOGD(TAG, "Response sucessful" + resposneObject );
latestPostTitle = new String[resposneObject.size()];
latestPostImage = new String[resposneObject.size()];
latestPostId = new Double[resposneObject.size()];
latestPostDate = new String[resposneObject.size()];
for(int i=0;i<resposneObject.size();++i){
mapLatestPost = (Map<String,Object>)resposneObject.get(i);
mapLatestTitle = (Map<String, Object>) mapLatestPost.get("title");
latestPostTitle[i] = (String) mapLatestTitle.get("rendered");
mapLatestContent = (Map<String, Object>) mapLatestPost.get("content");
latestPostImage[i] = (String) mapLatestContent.get("medium");
latestPostId[i] = (Double) mapLatestPost.get("id");
latestPostDate[i] = (String) mapLatestPost.get("date");
}
答案 7 :(得分:6)
这是一个基于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);
}
答案 8 :(得分:4)
所以不要那样做!
您有两种选择:
运行选择以获取结果集的COUNT,如果此计数不为零,则仅提取数据;或
使用其他类型的查询(获取结果集)并检查它是否有0或更多结果。它应该有1,所以从你的结果集合中拉出它就完成了。
我同意Cletus的第二个建议。它提供比(可能)2个查询更好的性能。也少工作。
答案 9 :(得分:4)
我建议有另一种选择:
Query query = em.createQuery("your query");
List<Element> elementList = query.getResultList();
return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);
这可以防止Null Pointer Exception,保证只返回1个结果。
答案 10 :(得分:3)
org.hibernate.query.Query中的未记录方法uniqueResultOptional
应该可以解决问题。您无需接听NoResultException
,而只需拨打query.uniqueResultOptional().orElse(null)
。
答案 11 :(得分:2)
结合现有答案的有用位(限制结果数量,检查结果是唯一的)并使用已建立的方法名称(Hibernate),我们得到:
/**
* Return a single instance that matches the query, or null if the query returns no results.
*
* @param query query (required)
* @param <T> result record type
* @return record or null
*/
public static <T> T uniqueResult(@NotNull TypedQuery<T> query) {
List<T> results = query.setMaxResults(2).getResultList();
if (results.size() > 1) throw new NonUniqueResultException();
return results.isEmpty() ? null : results.get(0);
}
答案 12 :(得分:2)
我使用List<?> myList = query.getResultList();
并检查myList.size()
是否等于零来解决这个问题。
答案 13 :(得分:1)
这是另一个扩展,这次是在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)
}
答案 14 :(得分:1)
这是与其他人建议的相同的逻辑(获取resultList,返回其唯一元素或null),使用Google Guava和TypedQuery。
public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
return Iterables.getOnlyElement(query.getResultList(), null);
}
请注意,如果结果集有多个结果,Guava将返回非直观的IllegalArgumentException。 (该异常对getOnlyElement()的客户端有意义,因为它将结果列表作为其参数,但对于getSingleResultOrNull()的客户端则不太容易理解。)
答案 15 :(得分:0)
如果您可以使用新的 JPA 功能,我更喜欢 @Serafins 的回答,但这是一种相当直接的方法,我很惊讶之前没有提到过:
try {
return (Profile) query.getSingleResult();
} catch (NoResultException ignore) {
return null;
}
答案 16 :(得分:0)
From JPA 2.2,而不是.getResultList()
并检查列表是否为空或创建流,您可以返回流并获取第一个元素。
.getResultStream()
.findFirst()
.orElse(null);
答案 17 :(得分:0)
我通过获取结果列表然后检查其是否为空来实现这一目标
public boolean exist(String value) {
List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
return !options.isEmpty();
}
太烦人了,getSingleResult()
抛出异常
投掷:
答案 18 :(得分:0)
查看此代码:
nslookup <ingress_url>
调用return query.getResultList().stream().findFirst().orElse(null);
时可能会引发NullPointerException。
最好的方法是:
findFirst()
答案 19 :(得分:0)
因此,本页中的所有“尝试重写无异常”解决方案都存在一个小问题。它不会抛出NonUnique异常,也不会抛出一些错误的情况(见下文)。
我认为正确的解决方案是(也许)这个:
public static <L> L getSingleResultOrNull(TypedQuery<L> query) {
List<L> results = query.getResultList();
L foundEntity = null;
if(!results.isEmpty()) {
foundEntity = results.get(0);
}
if(results.size() > 1) {
for(L result : results) {
if(result != foundEntity) {
throw new NonUniqueResultException();
}
}
}
return foundEntity;
}
如果列表中有0个元素,则返回null;如果列表中有不同的元素,则返回非唯一,但如果未正确设计其中一个select,则返回非唯一,并且返回同一个对象超过一次。
随意发表评论。
答案 20 :(得分:-1)
那对我有用:
Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;