Ich habe eine insertOrUpdate
Methode, die ein einfügt, Entity
wenn es nicht existiert, oder es aktualisiert, wenn es existiert. Um dies zu aktivieren, muss ich findByIdAndForeignKey
, wenn es zurückgegeben hat, null
einfügen, wenn nicht, dann aktualisieren. Das Problem ist, wie überprüfe ich, ob es existiert? Also habe ich es versucht getSingleResult
. Aber es löst eine Ausnahme aus, wenn die
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;
}
aber getSingleResult
wirft ein Exception
.
Vielen Dank
getSingleResult()
wird in Situationen wie: " Ich bin absolut sicher, dass dieser Datensatz existiert. Erschieß mich, wenn es nicht existiert " verwendet. Ich möchte nichtnull
jedes Mal testen, wenn ich diese Methode verwende, da ich sicher bin , dass sie nicht zurückgegeben wird. Andernfalls verursacht es viel Boilerplate und defensive Programmierung. Und wenn der Datensatz wirklich nicht existiert (im Gegensatz zu dem, was wir angenommen haben), ist es viel besser, ihn zu habenNoResultException
, alsNullPointerException
einige Zeilen später. NatürlichgetSingleResult()
wäre es fantastisch, zwei Versionen von zu haben, aber wenn ich eine abholenIch habe die Logik in der folgenden Hilfsmethode gekapselt.
quelle
Versuchen Sie dies in Java 8:
quelle
.orElse(null)
Hier ist eine gute Option dafür:
quelle
TypedQuery<T>
, in welchem Fall dasgetResultList()
dann schon richtig alsList<T>
.fetch()
der Entität ist sie möglicherweise nicht vollständig ausgefüllt. Siehe stackoverflow.com/a/39235828/661414setMaxResults()
es eine fließende Oberfläche hat, damit Sie schreiben könnenquery.setMaxResults(1).getResultList().stream().findFirst().orElse(null)
. Dies sollte das effizienteste Aufrufschema in Java 8+ sein.Spring hat hierfür eine Utility-Methode :
quelle
Ich habe getan (in Java 8):
quelle
Ab JPA 2.2 können Sie anstelle von
.getResultList()
und überprüfen, ob die Liste leer ist oder einen Stream erstellen, den Stream zurückgeben und das erste Element übernehmen.quelle
Wenn Sie den Try / Catch-Mechanismus verwenden möchten, um dieses Problem zu lösen, können Sie sich wie if / else verhalten. Ich habe try / catch verwendet, um einen neuen Datensatz hinzuzufügen, wenn ich keinen vorhandenen gefunden habe.
quelle
Hier ist eine typisierte / generische Version, die auf der Implementierung von Rodrigo IronMan basiert:
quelle
Es gibt eine Alternative, die ich empfehlen würde:
Dies schützt vor einer Nullzeiger-Ausnahme und garantiert, dass nur 1 Ergebnis zurückgegeben wird.
quelle
Also tu das nicht!
Sie haben zwei Möglichkeiten:
Führen Sie eine Auswahl aus, um den COUNT Ihrer Ergebnismenge zu erhalten, und ziehen Sie die Daten nur ein, wenn diese Anzahl ungleich Null ist. oder
Verwenden Sie die andere Art von Abfrage (die eine Ergebnismenge erhält) und prüfen Sie, ob 0 oder mehr Ergebnisse vorliegen. Es sollte 1 haben, also ziehen Sie das aus Ihrer Ergebnissammlung und Sie sind fertig.
Ich würde dem zweiten Vorschlag in Übereinstimmung mit Cletus folgen. Es bietet eine bessere Leistung als (möglicherweise) 2 Abfragen. Auch weniger Arbeit.
quelle
Durch Kombinieren der nützlichen Bits der vorhandenen Antworten (Begrenzen der Anzahl der Ergebnisse, Überprüfen, ob das Ergebnis eindeutig ist) und Verwenden des Namens der stabilisierbaren Methode (Ruhezustand) erhalten wir:
quelle
Die undokumentierte Methode
uniqueResultOptional
in org.hibernate.query.Query sollte den Trick ausführen. Anstatt einen zu fangenNoResultException
, können Sie einfach anrufenquery.uniqueResultOptional().orElse(null)
.quelle
Ich habe dies gelöst, indem ich verwendet
List<?> myList = query.getResultList();
und überprüft habe, ob esmyList.size()
gleich Null ist.quelle
Hier ist die gleiche Logik wie von anderen vorgeschlagen (Abrufen der Ergebnisliste, Zurückgeben des einzigen Elements oder Null) unter Verwendung von Google Guava und einer TypedQuery.
Beachten Sie, dass Guava die nicht intuitive IllegalArgumentException zurückgibt, wenn die Ergebnismenge mehr als ein Ergebnis enthält. (Die Ausnahme ist für Clients von getOnlyElement () sinnvoll, da sie die Ergebnisliste als Argument verwendet, für Clients von getSingleResultOrNull () jedoch weniger verständlich ist.)
quelle
Hier ist eine weitere Erweiterung, diesmal in Scala.
Mit diesem Zuhälter:
quelle
Schauen Sie sich diesen Code an:
return query.getResultList().stream().findFirst().orElse(null);
Wenn
findFirst()
aufgerufen wird, kann möglicherweise eine NullPointerException ausgelöst werden.Der beste Ansatz ist:
return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);
quelle
Die gesamte Lösung "Versuchen Sie ausnahmslos, neu zu schreiben" auf dieser Seite weist daher ein kleines Problem auf. Entweder wird keine NonUnique-Ausnahme ausgelöst, oder es wird auch in einigen falschen Fällen eine Ausnahme ausgelöst (siehe unten).
Ich denke, die richtige Lösung ist (vielleicht) folgende:
Es wird mit null zurückgegeben, wenn die Liste 0 Elemente enthält, und es wird nicht eindeutig zurückgegeben, wenn die Liste verschiedene Elemente enthält. Es wird jedoch nicht eindeutig zurückgegeben, wenn eines Ihrer ausgewählten Elemente nicht ordnungsgemäß entworfen wurde und dasselbe Objekt mehrmals zurückgibt.
Fühlen Sie sich frei zu kommentieren.
quelle
Ich habe dies erreicht, indem ich eine Ergebnisliste erhalten und dann überprüft habe, ob sie leer ist
Es ist so nervig, dass es
getSingleResult()
Ausnahmen gibtWürfe:
quelle
Das funktioniert bei mir:
quelle