Saya memiliki insertOrUpdate
metode yang memasukkan Entity
jika tidak ada atau memperbaruinya jika ada. Untuk mengaktifkan ini, saya harus findByIdAndForeignKey
, jika dikembalikan null
masukkan jika tidak kemudian perbarui. Masalahnya adalah bagaimana cara memeriksa apakah itu ada? Jadi saya mencoba getSingleResult
. Tapi itu membuat pengecualian jika
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;
}
tapi getSingleResult
melempar Exception
.
Terima kasih
getSingleResult()
digunakan dalam situasi seperti: " Saya sangat yakin bahwa rekaman ini ada. Tembak saya jika tidak ". Saya tidak ingin mengujinull
setiap kali saya menggunakan metode ini karena saya yakin itu tidak akan mengembalikannya. Jika tidak, itu menyebabkan banyak pemrograman boilerplate dan defensif. Dan jika record benar-benar tidak ada (berlawanan dengan apa yang kita asumsikan), akan lebih baikNoResultException
jika dibandingkan denganNullPointerException
beberapa baris kemudian. Tentu saja memiliki dua versigetSingleResult()
akan luar biasa, tetapi jika saya harus mengambil satu ...Saya merangkum logika dalam metode pembantu berikut.
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(); } }
sumber
Coba ini di Java 8:
sumber
.orElse(null)
Berikut opsi yang bagus untuk melakukan ini:
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); }
sumber
TypedQuery<T>
meskipun, dalam halgetResultList()
ini maka sudah diketik dengan benar sebagai fileList<T>
.fetch()
entitas mungkin tidak terisi seluruhnya. Lihat stackoverflow.com/a/39235828/661414setMaxResults()
memiliki antarmuka yang lancar sehingga Anda dapat menulisquery.setMaxResults(1).getResultList().stream().findFirst().orElse(null)
. Ini harus menjadi skema panggilan paling efisien di Java 8+.Spring memiliki metode utilitas untuk ini:
TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class); ... return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
sumber
Saya telah selesai (di Java 8):
query.getResultList().stream().findFirst().orElse(null);
sumber
Dari JPA 2.2 , alih-alih
.getResultList()
dan memeriksa apakah daftar kosong atau membuat aliran, Anda dapat mengembalikan aliran dan mengambil elemen pertama..getResultStream() .findFirst() .orElse(null);
sumber
Jika Anda ingin menggunakan mekanisme coba / tangkap untuk menangani masalah ini .. maka dapat digunakan untuk bertindak seperti if / else. Saya menggunakan coba / tangkap untuk menambahkan rekor baru ketika saya tidak menemukan yang sudah ada.
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); }
sumber
Berikut adalah versi yang diketik / generik, berdasarkan implementasi 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); }
sumber
Ada alternatif lain yang saya rekomendasikan:
Query query = em.createQuery("your query"); List<Element> elementList = query.getResultList(); return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);
Pengamanan ini terhadap Pengecualian Null Pointer, menjamin hanya 1 hasil yang dikembalikan.
sumber
Jadi jangan lakukan itu!
Anda memiliki dua opsi:
Jalankan pilihan untuk mendapatkan JUMLAH kumpulan hasil Anda, dan hanya menarik data jika hitungan ini bukan nol; atau
Gunakan jenis kueri lain (yang mendapatkan kumpulan hasil) dan periksa apakah memiliki 0 hasil atau lebih. Ini harus memiliki 1, jadi keluarkan dari koleksi hasil Anda dan Anda selesai.
Saya setuju dengan saran kedua, sesuai dengan Cletus. Ini memberikan kinerja yang lebih baik daripada (berpotensi) 2 kueri. Juga lebih sedikit pekerjaan.
sumber
Menggabungkan bit-bit berguna dari jawaban yang ada (membatasi jumlah hasil, memeriksa bahwa hasilnya unik) dan menggunakan nama metode estabilshed (Hibernate), kita mendapatkan:
/** * 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); }
sumber
Metode tidak berdokumen
uniqueResultOptional
di org.hibernate.query.Query harus melakukan triknya. Alih-alih harus menangkap,NoResultException
Anda bisa meneleponquery.uniqueResultOptional().orElse(null)
.sumber
Saya menyelesaikan ini dengan menggunakan
List<?> myList = query.getResultList();
dan memeriksa apakahmyList.size()
sama dengan nol.sumber
Berikut logika yang sama seperti yang disarankan orang lain (dapatkan resultList, kembalikan satu-satunya elemen atau null), menggunakan Google Guava dan TypedQuery.
public static <T> getSingleResultOrNull(final TypedQuery<T> query) { return Iterables.getOnlyElement(query.getResultList(), null); }
Perhatikan bahwa Guava akan mengembalikan IllegalArgumentException yang tidak intuitif jika rangkaian hasil memiliki lebih dari satu hasil. (Pengecualian masuk akal bagi klien getOnlyElement (), karena ini mengambil daftar hasil sebagai argumennya, tetapi kurang dapat dimengerti oleh klien getSingleResultOrNull ().)
sumber
Berikut ekstensi lainnya, kali ini di Scala.
customerQuery.getSingleOrNone match { case Some(c) => // ... case None => // ... }
Dengan germo ini:
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) }
sumber
Jadi semua solusi "coba tulis ulang tanpa pengecualian" di halaman ini memiliki masalah kecil. Entah itu tidak memunculkan pengecualian NonUnique, juga tidak melemparkannya dalam beberapa kasus yang salah (lihat di bawah).
Saya pikir solusi yang tepat adalah (mungkin) ini:
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; }
Ini mengembalikan dengan null jika ada 0 elemen dalam daftar, mengembalikan nonunique jika ada elemen berbeda dalam daftar, tetapi tidak mengembalikan nonunique ketika salah satu pilihan Anda tidak dirancang dengan benar dan mengembalikan objek yang sama lebih dari satu kali.
Jangan ragu untuk berkomentar.
sumber
getResultList().stream().distinct().reduce((a, b) -> {throw new NonUniqueResultException();}).orElse(null);
Lihat kode ini:
return query.getResultList().stream().findFirst().orElse(null);
Saat
findFirst()
dipanggil mungkin bisa melontarkan NullPointerException.pendekatan terbaik adalah:
return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);
sumber
Saya mencapai ini dengan mendapatkan daftar hasil kemudian memeriksa apakah itu kosong
public boolean exist(String value) { List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList(); return !options.isEmpty(); }
Itu sangat menjengkelkan yang
getSingleResult()
melempar pengecualianMelempar:
sumber
Itu berhasil bagi saya:
Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult()); return opt.isPresent() ? opt.get() : null;
sumber