Spring-Data-JPA açıklama için setMaxResults?


128

Spring-Data-JPA'yı projeme dahil etmeye çalışıyorum. Kafamı karıştıran bir şey, açıklama ile setMaxResults (n) 'a nasıl ulaşabilirim?

örneğin benim kodum:

public interface UserRepository extends CrudRepository<User , Long>
{
  @Query(value="From User u where u.otherObj = ?1 ")
  public User findByOhterObj(OtherObj otherObj);
}

one (and only one)Kullanıcıyı yalnızca otherObj'den döndürmem gerekiyor , ancak maxResults'a açıklama eklemenin bir yolunu bulamıyorum. Biri bana bir ipucu verebilir mi?

(mysql şikayet ediyor:

com.mysql.jdbc.JDBC4PreparedStatement@5add5415: select user0_.id as id100_, user0_.created as created100_ from User user0_ where user0_.id=2 limit ** NOT SPECIFIED **
WARN  util.JDBCExceptionReporter - SQL Error: 0, SQLState: 07001
ERROR util.JDBCExceptionReporter - No value specified for parameter 2

)

Bir bağlantı buldum: https://jira.springsource.org/browse/DATAJPA-147 , denedim ama başarısız oldum. Şimdi mümkün değil mi? Spring-Data'da neden bu kadar önemli bir özellik yerleşik değil?

Bu özelliği manuel olarak uygularsam:

public class UserRepositoryImpl implements UserRepository

İçinde tonlarca önceden tanımlanmış yöntem uygulamalıyım CrudRepository, bu korkunç olurdu.

ortamlar: spring-3.1, spring-data-jpa-1.0.3.RELEASE.jar, spring-data-commons-core-1.1.0.RELEASE.jar

Yanıtlar:


176

Spring Data JPA 1.7.0 itibariyle (Evans sürüm treni).

Yeni tanıtılan Topve aşağıdaki Firstgibi sorgu yöntemlerini tanımlamanıza izin veren anahtar kelimeleri kullanabilirsiniz :

findTop10ByLastnameOrderByFirstnameAsc(String lastname);

Spring Data, sonuçları otomatik olarak tanımladığınız sayı ile sınırlayacaktır (atlanırsa varsayılan olarak 1'dir). Sonuçların sıralanmasının burada alakalı hale geldiğine dikkat edin ( OrderByörnekte görüldüğü gibi bir cümle yoluyla veya Sortyönteme bir parametre vererek). Spring Data Evans sürüm treninin yeni özelliklerini kapsayan blog gönderisinde veya belgelerde daha fazla bilgi edinin .

Önceki sürümler için

Spring Data, yalnızca veri dilimlerini almak için Pageable, talep eden tarafta bir arayüz Pageve şeylerin sonuç tarafında bir soyutlama ile gelen sayfalandırma soyutlamasını kullanır . Böylece başlayabilirsin

public interface UserRepository extends Repository<User, Long> {

  List<User> findByUsername(String username, Pageable pageable);
}

ve şu şekilde kullanın:

Pageable topTen = new PageRequest(0, 10);
List<User> result = repository.findByUsername("Matthews", topTen);

Sonucun bağlamını bilmeniz gerekiyorsa (gerçekte hangi sayfa? İlk sayfa mı? Toplamda kaç tane var?), PageDönüş türü olarak kullanın :

public interface UserRepository extends Repository<User, Long> {

  Page<User> findByUsername(String username, Pageable pageable);
}

Müşteri kodu daha sonra şuna benzer bir şey yapabilir:

Pageable topTen = new PageRequest(0, 10);
Page<User> result = repository.findByUsername("Matthews", topTen);
Assert.assertThat(result.isFirstPage(), is(true));

PageMetadata hesaplamak için toplamda kaç öğe olduğunu bulmamız gerektiğinden, dönüş türü olarak kullanmanız durumunda yürütülecek gerçek sorgunun bir sayım projeksiyonunu tetikleyeceğimizden değil . Bunun ötesinde, PageRequestistikrarlı sonuçlar elde etmek için gerçekten sıralama bilgileriyle donattığınızdan emin olun . Aksi takdirde, sorguyu iki kez tetikleyebilir ve alttaki veriler değişmeden bile farklı sonuçlar alabilirsiniz.


14
Teşekkürler, ancak yine de "ek açıklama tabanlı" bir çözüm umuyorum. Çünkü "Sayfa / Sayfalandırılabilir" bu durumda çok abartılı. Ve müşterinin 'bir ve tek' sonucu almak için bir Sayfalandırılabilir / Sayfa oluşturması gerekiyor ... Kullanması çok kolay değil. Görünüşe göre Spring-Data'dan siz sorumlusunuz, umarım bu soruna daha fazla bakabilirsiniz: stackoverflow.com/questions/9276461/… . Spring-Data'nın hatası olup olmadığını onaylayabilir misin?
— smallufo

1
+ bu işe yarıyor, teşekkürler, ancak ek açıklama tabanlı bir çözüm yeni sürümlerde daha iyi olurdu
— azerafati

1
burada sınırlı bir sorgu istiyorsak tamamen gereksiz olan bir sayma sorgusu tetiklenir.
— azerafati

1
ListYöntemin dönüş türü olarak kullanırsanız değil .
— Oliver Drotbohm

3
Sanırım Topve Firstanahtar kelimeler @Queryek açıklama kullanan yöntemler için geçerli değil mi? Yalnızca yöntem adına dayalı sorgu oluşturmayı kullananlar mı?
— Ruslan Stelmachenko

106

Java 8 ve Spring Data 1.7.0 kullanıyorsanız, bir @Queryek açıklamayı maksimum sonuçları ayarlayarak birleştirmek istiyorsanız varsayılan yöntemleri kullanabilirsiniz :

public interface UserRepository extends PagingAndSortingRepository<User,Long> {
  @Query("from User u where ...")
  List<User> findAllUsersWhereFoo(@Param("foo") Foo foo, Pageable pageable);

  default List<User> findTop10UsersWhereFoo(Foo foo) {
    return findAllUsersWhereFoo(foo, new PageRequest(0,10));
  }

}

3
tek bir sonuç için potansiyel olarak yararlıStream<User> ... {...} default Optional<User> ... { ...findAny() }
— xenoterracide

28

"A setMaxResults (n) by annotation" eşdeğerini aşağıdaki gibi sağlamanın bir yolu vardır:

public interface ISomething extends JpaRepository<XYZ, Long>
{
    @Query("FROM XYZ a WHERE a.eventDateTime < :before ORDER BY a.eventDateTime DESC")
    List<XYZ> findXYZRecords(@Param("before") Date before, Pageable pageable);
}

Parametre olarak bir sayfalanabilir gönderildiğinde, bu hile yapmalıdır. Örneğin, ilk 10 kaydı almak için sayfalanabilirliği bu değere ayarlamanız gerekir:

new PageRequest(0, 10)

Sayfalandırılabilir kullanıyorsanız, o zaman <XYZ>, Liste <XYZ> değil
— Arundev

@Arundev yanlış - Listmükemmel çalışıyor (ve daha önceki bircount yorumda belirtildiği gibi gereksiz sorguları önler )
— Janaka Bandara

21

Spring Data Evans'ı kullanın (1.7.0 YAYIN)

Spring Data JPA'nın yeni sürümü, Evans adlı başka bir modül listesiyle birlikte anahtar kelimeleri kullanma Top20ve Firstsorgu sonucunu sınırlama özelliğine sahiptir ,

yani şimdi yazabilirsin

List<User> findTop20ByLastname(String lastname, Sort sort);

veya

List<User> findTop20ByLastnameOrderByIdDesc(String lastname);

veya tek bir sonuç için

List<User> findFirstByLastnameOrderByIdDesc(String lastname);

5
İsteğe bağlı <Kullanıcı> findFirstByLastnameOrderByIdDesc (Dize soyadı);
— krmanish007

İlk 20 sonucu aldıktan sonra, sayfalandırmayı kullanarak web sitesinde sonraki sayfaya gittiğimde sonraki 20 sonucu nasıl elde ederim?
— kittu

@kittu, bu tabii ki başka bir soru ama bir Pageablenesneyi iletmeniz gerekiyor . bahar belgelerine göz
— atın

Neden İLK olarak belirtilmişse yöntemi lanet bir Liste döndürdüler ??
— Vasile Surdu

13

Benim için en iyi seçim yerel sorgu:

@Query(value="SELECT * FROM users WHERE other_obj = ?1 LIMIT 1", nativeQuery = true)
User findByOhterObj(OtherObj otherObj);

Hibernate'de sınırın desteklenip desteklenmediğinden emin değilim: forum.hibernate.org/viewtopic.php?f=9&t=939314
— Witold Kaczurba

2
Tüm konsepti bozuyor! Bunun yerine EntityManager kullanın!
— Spektakulatius

@ Code.IT KISS konseptini yayıyorum. Bunun dışında JPA nativeQuery ek açıklama parametresi göz ardı edilmemesi için eklendi.
— Grigory Kislin

@GKislin, findLimitOneByOtherObj gibi bir yöntemi yeniden adlandırmak zorunda kalacağından. Ayrıca, other_obj benzersiz değilse yanlış sonuca yol açan bir OrderBy eklemeyi unuttunuz. Aksi takdirde, benzersiz bir sütundaki bir nerede ifadesi sınırsız bir şekilde yeterli olmalıdır
— Spektakulatius

LIMIT anahtar kelime hazırda bekletme değil, postgres / mysql
— Acewin

5

Sınıfınız @Repositorygenişlerse JpaRepositoryaşağıdaki örneği kullanabilirsiniz.

int limited = 100;
Pageable pageable = new PageRequest(0,limited);
Page<Transaction> transactionsPage = transactionRepository.findAll(specification, pageable);
return transactionsPage.getContent();

getContent bir List<Transaction>.


işlemRepository.findByFirstNameAndLastName (ad, soyad) gibi sorguda 2 koşulum varsa ne olur? çalışacak mı Bu istisna alıyorum org.springframework.data.mapping.PropertyReferenceException: Board türü için özellik oluşturma bulunamadı.
— Shailesh

4

Ayrıca @QueryHints kullanılarak da mümkündür. Aşağıdaki örnek org.eclipse.persistence.config.QueryHints # JDBC_MAX_ROWS kullanıyor

@Query("SELECT u FROM User u WHERE .....")
@QueryHints(@QueryHint(name = JDBC_MAX_ROWS, value = "1"))
Voter findUser();

Bu kodu test ettim ama çalışmıyor. İstisna yok, ama daha uygun sonuç yok. Ayrıca, QueryHints hakkında belgeler çok incedir. Aşağıya bakınız. docs.spring.io/spring-data/jpa/docs/1.7.1.RELEASE/reference/…
— bogdan.rusu

IIRC, bir sorgu ipucunun izleneceğine dair hiçbir garanti yoktur . Bu, uygulamaya "dost tavsiyeleri" aktarmanın bir yoludur.
— Priidu Neemre

@QueryHints({@QueryHint(name = org.hibernate.annotations.FETCH_SIZE, value = "1")})Hibernate'de deniyorum , ancak takma ad :( çalışmıyor
— Grigory Kislin

2
org.hibernate.annotations.FETCH_SIZE getirme boyutu, sınırı değil, maksimum sonuçları değil. Hiber cant
— Zhuravskiy Vitaliy

4

new PageRequest(0,10)daha yeni Bahar sürümlerinde çalışmıyor (kullanıyorum 2.2.1.RELEASE). Temel olarak, kurucu, Sorttür olarak ek bir parametre aldı . Dahası, yapıcı, protectedya onun alt sınıflarından birini kullanmanız ya da ofstatik yöntemini çağırmanız gerekir :

PageRequest.of(0, 10, Sort.sort(User.class).by(User::getFirstName).ascending()))

Ayrıca Sortparametre kullanımını atlayabilir ve örtük olarak varsayılan sıralamayı kullanabilirsiniz (pk'ye göre sıralama, vb.):

PageRequest.of(0, 10)

İşlev bildiriminiz şöyle bir şey olmalıdır:

List<User> findByUsername(String username, Pageable pageable)

ve işlev şöyle olacaktır:

userRepository.findByUsername("Abbas", PageRequest.of(0,10, Sort.sort(User.class).by(User::getLastName).ascending());
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.