JPA getSingleResult () या अशक्त


136

मेरे पास एक ऐसा 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

धन्यवाद

जवाबों:


266

एक अपवाद को फेंकना getSingleResult()यह बताता है कि यह कैसे पाया जा सकता है। व्यक्तिगत रूप से मैं इस तरह का एपीआई नहीं खड़ा कर सकता। यह कोई वास्तविक लाभ के लिए संयमपूर्ण अपवाद से निपटने के लिए मजबूर करता है। आपको बस एक कोशिश करने वाले ब्लॉक में कोड को लपेटना होगा।

वैकल्पिक रूप से आप किसी सूची के लिए क्वेरी कर सकते हैं और देख सकते हैं कि क्या वह खाली है। यह एक अपवाद नहीं है। चूंकि आप तकनीकी रूप से एक प्राथमिक कुंजी लुकअप नहीं कर रहे हैं, इसलिए कई परिणाम हो सकते हैं (भले ही एक, दोनों या आपकी विदेशी कुंजी या बाधाओं का संयोजन अभ्यास में यह असंभव बना देता है) इसलिए यह संभवतः अधिक उपयुक्त समाधान है।


115
मैं सहमत नहीं हूं, getSingleResult()जैसे स्थितियों में उपयोग किया जाता है: " मुझे पूरी तरह से यकीन है कि यह रिकॉर्ड मौजूद है। मुझे गोली मारो अगर यह नहीं है "। मैं nullइस पद्धति का उपयोग करने के लिए हर बार परीक्षण नहीं करना चाहता क्योंकि मुझे यकीन है कि यह इसे वापस नहीं करेगा। अन्यथा यह बहुत सारे बॉयलरप्लेट और रक्षात्मक प्रोग्रामिंग का कारण बनता है। और अगर रिकॉर्ड वास्तव में मौजूद नहीं है (जैसा कि हमने मान लिया है उसके विपरीत), तो बाद में कुछ पंक्तियों NoResultExceptionकी तुलना में बेहतर है NullPointerException। निश्चित रूप से दो संस्करण getSingleResult()होने के कारण भयानक होगा, लेकिन अगर मुझे एक को चुनना है ...
टॉमाज़ नर्कविक्ज़

8
@ क्लेटस नल वास्तव में एक डेटाबेस के लिए एक वैध वापसी मूल्य है।
बिल रोसमस

12
@TomaszNurkiewicz यह एक अच्छी बात है। हालाँकि, ऐसा लगता है कि "getSingleResultOrNull" के कुछ प्रकार होने चाहिए। मुझे लगता है कि आप इस तरह के लिए एक आवरण बना सकते हैं।
cbmeeks

2
यहाँ कुछ जानकारी है अपवाद के लाभ में getSingleResult () से फेंकना शुरू करें: क्वेरी का उपयोग एक पंक्ति में एकल स्तंभ के मूल्य सहित लगभग कुछ भी प्राप्त करने के लिए किया जा सकता है। यदि getSingleResult () शून्य हो जाएगा, तो आप यह नहीं बता सकते कि क्वेरी किसी पंक्ति से मेल नहीं खाती या क्वेरी पंक्ति से मेल खाती है या नहीं, लेकिन चयनित कॉलम में इसके मान के रूप में रिक्त है। से: stackoverflow.com/a/12155901/1242321
user1242321

5
इसे वैकल्पिक <T> वापस करना चाहिए। गुम मूल्यों को इंगित करने का यह एक अच्छा तरीका है।
विवेक कोठारी

33

मैंने निम्नलिखित सहायक विधि में तर्क को समझाया।

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
ध्यान दें कि आप Query.setMaxResults (1) को कॉल करके थोड़ा अधिक इष्टतम हो सकते हैं। अफसोस की बात है, क्योंकि क्वेरी के स्टेटफुल होने के बाद, आप Query.getMaxResults () का मान कैप्चर करना चाहेंगे और ऑब्जेक्ट को अंत में ब्लॉक करने का प्रयास करेंगे, और यदि Query.getFirstResult () कुछ भी दिलचस्प लौटाता है तो शायद पूरी तरह से विफल हो जाए।
पैट्रिक लिंस्की

हमने इसे अपनी परियोजना पर कैसे लागू किया है। इस कार्यान्वयन के साथ कभी भी कोई समस्या नहीं थी
चलना

25

यह जावा 8 में आज़माएँ:

Optional first = query.getResultList().stream().findFirst();

3
आप जोड़कर वैकल्पिक से छुटकारा पा सकते.orElse(null)
जस्टिन रोवे

24

यहाँ यह करने के लिए एक अच्छा विकल्प है:

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);
}

2
साफ! TypedQuery<T>हालांकि मैं स्वीकार करता हूं कि किस स्थिति में getResultList()पहले से ही सही ढंग से टाइप किया गया है List<T>
रुप

fetch()इकाई के साथ संयोजन में पूरी तरह से आबादी नहीं हो सकती है। देखें stackoverflow.com/a/39235828/661414
Leukipp

1
यह एक बहुत अच्छा तरीका है। ध्यान दें कि setMaxResults()एक धाराप्रवाह इंटरफ़ेस है ताकि आप लिख सकें query.setMaxResults(1).getResultList().stream().findFirst().orElse(null)। यह जावा 8+ में सबसे कुशल कॉल योजना होनी चाहिए।
डिर्क हिलब्रैच


15

मैंने किया है (जावा 8 में):

query.getResultList().stream().findFirst().orElse(null);

क्वेरी से आपका क्या मतलब है?
एनरिको ज्यूरिन

आप HibernateQuery मतलब है? यदि मैं शुद्ध JPA एपीआई का उपयोग करना चाहता हूं तो क्या होगा?
Javax.persistence.Query

2
@EnricoGiurin, मैंने स्निपेट संपादित किया है। बढ़िया कार्य करना। कोई कोशिश नहीं पकड़, और कोई सूची। आकार की जाँच करें। सबसे अच्छा एक लाइनर समाधान।
लोवाबिल

10

JPA 2.2 से , इसके बजाय .getResultList()और जाँच करें कि क्या सूची खाली है या एक स्ट्रीम बना रहा है तो आप स्ट्रीम वापस कर सकते हैं और पहला तत्व ले सकते हैं।

.getResultStream()
.findFirst()
.orElse(null);

7

यदि आप इस समस्या को संभालने के लिए ट्राइ / कैच मैकेनिज्म का उपयोग करना चाहते हैं .. तो इसका उपयोग इफ़ / वर की तरह किया जा सकता है। जब मैंने एक मौजूदा रिकॉर्ड नहीं पाया तो मैंने एक नया रिकॉर्ड जोड़ने के लिए कोशिश / कैच का इस्तेमाल किया।

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

यहां रॉड्रिगो आयरनमैन के कार्यान्वयन के आधार पर एक टाइप / जेनरिक संस्करण है:

 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);
}

5

एक विकल्प है जो मैं सुझाऊंगा:

Query query = em.createQuery("your query");
List<Element> elementList = query.getResultList();
return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);

नल सूचक अपवाद के खिलाफ यह सुरक्षा, केवल 1 परिणाम की गारंटी देता है।


4

तो ऐसा मत करो!

आपके पास दो विकल्प हैं:

  1. अपने परिणाम सेट के COUNT को प्राप्त करने के लिए एक चयन चलाएँ, और केवल डेटा में खींच लें यदि यह गिनती गैर-शून्य है; या

  2. दूसरी तरह के क्वेरी का उपयोग करें (जो एक परिणाम सेट प्राप्त करता है) और जांचें कि क्या इसके 0 या अधिक परिणाम हैं। इसमें 1 होना चाहिए, ताकि आपके परिणाम संग्रह से बाहर निकलें और आपका काम हो जाए।

मैं Cletus के साथ समझौते में, दूसरे सुझाव के साथ जाऊँगा। यह (संभावित) 2 प्रश्नों की तुलना में बेहतर प्रदर्शन देता है। काम भी कम।


1
विकल्प 3 की कोशिश / पकड़ने NoResultException
Ced

3

मौजूदा उत्तरों के उपयोगी बिट्स को संयोजित करना (परिणामों की संख्या को सीमित करना, यह देखना कि परिणाम अद्वितीय है) और estabilshed विधि नाम (हाइबरनेट) का उपयोग करके, हम प्राप्त करते हैं:

/**
 * 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);
}

3

uniqueResultOptionalOrg.hibernate.query.Query में अनिर्दिष्ट विधि चाल करना चाहिए। इसके बजाय NoResultExceptionआप को पकड़ने के लिए आप बस फोन कर सकते हैं query.uniqueResultOptional().orElse(null)


2

List<?> myList = query.getResultList();यदि myList.size()शून्य के बराबर है, तो मैंने इसका उपयोग करके और जाँच कर इसे हल किया ।


1

यहाँ वही तर्क दिया गया है, जैसा कि अन्य लोगों ने सुझाव दिया था (परिणाम प्राप्त करें, अपना एकमात्र तत्व या अशक्त लौटाएं), Google अमरूद और एक टाइपेडिक्यू का उपयोग करके।

public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
    return Iterables.getOnlyElement(query.getResultList(), null); 
}

ध्यान दें कि यदि परिणाम सेट के एक से अधिक परिणाम हैं, तो अमरूद अनजाने अवैध अवैधता को वापस कर देगा। (अपवाद getOnlyElement के ग्राहकों को समझ में आता है (), क्योंकि यह परिणाम सूची को अपने तर्क के रूप में लेता है, लेकिन getSingleResultOrNull () के ग्राहकों के लिए कम समझ में आता है।


1

यहाँ एक और विस्तार है, इस बार स्काला में।

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)
}

1

इस कोड को देखें:

return query.getResultList().stream().findFirst().orElse(null);

जब findFirst()कहा जाता है तो शायद NullPointerException को फेंक दिया जा सकता है।

सबसे अच्छा aproach है:

return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);


0

इसलिए इस पृष्ठ में "बिना किसी अपवाद के फिर से लिखना" के सभी समाधानों में एक मामूली समस्या है। या तो इसका नॉनइकनीक अपवाद नहीं फेंक रहा है, न ही इसे कुछ गलत मामलों में भी फेंक दें (नीचे देखें)।

मुझे लगता है कि उचित समाधान यह है (शायद):

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 तत्व है, तो nonunique लौटाता है यदि सूची में अलग-अलग तत्व हैं, लेकिन नॉनकिक नहीं लौट रहा है जब आपका कोई चयन ठीक से डिज़ाइन नहीं किया गया है और एक ही वस्तु को अधिक बार वापस करता है।

टिप्पणी करने के लिए स्वतंत्र महसूस करें।


0

मैंने रिजल्ट लिस्ट प्राप्त करके यह हासिल किया है, अगर यह खाली है तो जाँच करें

public boolean exist(String value) {
        List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
        return !options.isEmpty();
    }

यह इतना कष्टप्रद है कि getSingleResult()अपवादों को फेंकता है

फेंकता:

  1. NoResultException - अगर कोई परिणाम नहीं है
  2. NonUniqueResultException - अगर एक से अधिक परिणाम और कुछ अन्य अपवाद हैं कि आप उनके प्रलेखन से अधिक जानकारी प्राप्त कर सकते हैं

-3

यह मेरे लिए काम करता है:

Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.