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.