setMaxResults สำหรับคำอธิบายประกอบ Spring-Data-JPA?


128

ฉันพยายามรวม Spring-Data-JPA เข้ากับโครงการของฉัน สิ่งหนึ่งที่ทำให้ฉันสับสนคือฉันจะบรรลุ setMaxResults (n) ด้วยคำอธิบายประกอบได้อย่างไร

ตัวอย่างเช่นรหัสของฉัน:

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)User จาก otherObj เท่านั้น แต่ฉันหาวิธีใส่คำอธิบายประกอบ maxResults ไม่ได้ ใครช่วยให้คำแนะนำฉันได้ไหม

(mysql บ่น:

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

)

ฉันพบลิงค์: https://jira.springsource.org/browse/DATAJPA-147ฉันพยายาม แต่ล้มเหลว ตอนนี้ดูเหมือนจะเป็นไปไม่ได้แล้ว? เหตุใดคุณลักษณะสำคัญดังกล่าวจึงไม่รวมอยู่ใน Spring-Data

หากฉันใช้คุณสมบัตินี้ด้วยตนเอง:

public class UserRepositoryImpl implements UserRepository

ฉันต้องใช้วิธีการที่กำหนดไว้ล่วงหน้าCrudRepositoryเป็นจำนวนมากสิ่งนี้จะแย่มาก

สภาพแวดล้อม: spring-3.1, spring-data-jpa-1.0.3.RELEASE.jar, spring-data-commons-core-1.1.0.RELEASE.jar

คำตอบ:


176

ณ Spring Data JPA 1.7.0 (Evans release train)

คุณสามารถใช้คำหลักที่เพิ่งแนะนำTopและFirstให้คุณกำหนดวิธีการสืบค้นได้ดังนี้:

findTop10ByLastnameOrderByFirstnameAsc(String lastname);

Spring Data จะ จำกัด ผลลัพธ์โดยอัตโนมัติตามจำนวนที่คุณกำหนดไว้ (ค่าเริ่มต้นคือ 1 หากละเว้น) โปรดทราบว่าลำดับของผลลัพธ์จะมีความเกี่ยวข้องที่นี่ (ไม่ว่าจะผ่านOrderByประโยคตามที่เห็นในตัวอย่างหรือโดยการส่งSortพารามิเตอร์ไปยังเมธอด) อ่านเพิ่มเติมว่าในบล็อกโพสต์ครอบคลุมคุณสมบัติใหม่ของการเปิดตัวรถไฟฤดูใบไม้ผลิข้อมูลอีแวนส์หรือในเอกสาร

สำหรับรุ่นก่อนหน้า

ในการดึงเฉพาะส่วนของข้อมูล Spring Data จะใช้นามธรรมการแบ่งหน้าซึ่งมาพร้อมกับPageableอินเทอร์เฟซในด้านการร้องขอรวมถึงสิ่งที่เป็นPageนามธรรมในด้านผลลัพธ์ของสิ่งต่างๆ คุณสามารถเริ่มต้นด้วย

public interface UserRepository extends Repository<User, Long> {

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

และใช้มันดังนี้:

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

หากคุณต้องการทราบบริบทของผลลัพธ์ (แท้จริงแล้วเพจใดเป็นเพจแรกหรือไม่มีทั้งหมดกี่หน้า) ให้ใช้Pageเป็นประเภทผลตอบแทน:

public interface UserRepository extends Repository<User, Long> {

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

จากนั้นรหัสไคลเอ็นต์สามารถทำสิ่งนี้ได้:

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

ไม่ใช่ว่าเราจะเรียกใช้การคาดการณ์การนับของข้อความค้นหาจริงในกรณีที่คุณใช้Pageเป็นประเภทการส่งคืนเนื่องจากเราจำเป็นต้องค้นหาว่ามีองค์ประกอบทั้งหมดในการคำนวณข้อมูลเมตา ยิ่งไปกว่านั้นตรวจสอบให้แน่ใจว่าคุณได้จัดเตรียมPageRequestข้อมูลการเรียงลำดับเพื่อให้ได้ผลลัพธ์ที่มั่นคง มิฉะนั้นคุณอาจเรียกใช้การสืบค้นสองครั้งและได้ผลลัพธ์ที่แตกต่างกันแม้ว่าจะไม่มีการเปลี่ยนแปลงข้อมูลด้านล่างก็ตาม


14
ขอบคุณ แต่ฉันยังคงหวังว่าจะได้โซลูชัน "ตามคำอธิบายประกอบ" เนื่องจาก "Page / Pageable" มากเกินไปในกรณีนี้ และลูกค้าต้องสร้าง Pageable / Page เพื่อดึงผลลัพธ์ 'หนึ่งเดียว' ... มันไม่เป็นมิตรกับการใช้งาน และดูเหมือนว่าคุณจะอยู่ในความดูแลของฤดูใบไม้ผลิข้อมูลผมหวังว่าคุณจะสามารถมองเข้าไปในปัญหานี้: stackoverflow.com/questions/9276461/... คุณสามารถยืนยันได้หรือไม่ว่าเป็นบั๊กของ Spring-Data?
smallufo

1
+ ใช้งานได้ขอบคุณ แต่โซลูชันที่ใช้คำอธิบายประกอบจะดีกว่าในเวอร์ชันใหม่กว่า
azerafati

1
คิวรีแบบนับจะเริ่มทำงานที่นี่ซึ่งไม่จำเป็นโดยสิ้นเชิงหากเราต้องการแบบสอบถามที่ จำกัด
azerafati

1
ไม่ใช่ถ้าคุณใช้Listเป็นประเภทการส่งคืนของวิธีการ
Oliver Drotbohm

3
ฉันคิดว่าTopและFirstคำหลักไม่สามารถใช้ได้กับวิธีการที่ใช้@Queryคำอธิบายประกอบ? เฉพาะสิ่งที่ใช้การสร้างแบบสอบถามตามชื่อวิธีการ
Ruslan Stelmachenko

106

หากคุณใช้ Java 8 และ Spring Data 1.7.0 คุณสามารถใช้วิธีเริ่มต้นหากคุณต้องการรวม@Queryคำอธิบายประกอบเข้ากับการตั้งค่าผลลัพธ์สูงสุด:

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
อาจมีประโยชน์สำหรับผลลัพธ์เดียวStream<User> ... {...} default Optional<User> ... { ...findAny() }
xenoterracide

28

มีวิธีที่คุณสามารถระบุ "a setMaxResults (n) ที่เทียบเท่าด้วยคำอธิบายประกอบ" ดังต่อไปนี้:

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

สิ่งนี้ควรใช้เคล็ดลับเมื่อส่งเพจได้เป็นพารามิเตอร์ ตัวอย่างเช่นในการดึงข้อมูล 10 ระเบียนแรกที่คุณต้องตั้งค่าที่สามารถเพจได้เป็นค่านี้:

new PageRequest(0, 10)

หากคุณใช้ Pagable แสดงว่ากลับหน้า <XYZ> ไม่ใช่รายการ <XYZ>
Arundev

@Arundev ผิด - Listทำงานได้อย่างสมบูรณ์ (และหลีกเลี่ยงcountคำถามที่ไม่จำเป็นตามที่กล่าวไว้แล้วในความคิดเห็นก่อนหน้านี้ )
Janaka Bandara

21

ใช้ Spring Data Evans (1.7.0 RELEASE)

Spring Data JPA รุ่นใหม่พร้อมรายการโมดูลอื่นที่เรียกว่าEvansมีคุณสมบัติในการใช้คำหลักTop20และFirstเพื่อ จำกัด ผลการสืบค้น

ตอนนี้คุณสามารถเขียนได้

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

หรือ

List<User> findTop20ByLastnameOrderByIdDesc(String lastname);

หรือสำหรับผลลัพธ์เดียว

List<User> findFirstByLastnameOrderByIdDesc(String lastname);

5
ตัวเลือก <User> findFirstByLastnameOrderByIdDesc (String lastname);
krmanish007

หลังจากได้ผลลัพธ์ 20 อันดับแรกฉันจะได้ผลลัพธ์ 20 รายการถัดไปอย่างไรเมื่อฉันไปที่หน้าถัดไปบนเว็บไซต์โดยใช้การแบ่งหน้า
kittu

@kittu แน่นอนว่าเป็นอีกคำถามหนึ่ง แต่คุณต้องผ่านPageableวัตถุ ตรวจสอบเอกสารประกอบฤดูใบไม้ผลิ
azerafati

ทำไมพวกเขาถึงสร้างวิธีการส่งคืนรายการที่น่ารังเกียจถ้ามันระบุ FIRST ??
Vasile Surdu

13

ทางเลือกที่ดีที่สุดสำหรับฉันคือข้อความค้นหาดั้งเดิม:

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

ไม่แน่ใจว่า จำกัด การรองรับใน Hibernate หรือไม่: forum.hibernate.org/viewtopic.php?f=9&t=939314
Witold Kaczurba

2
พังทั้งคอนเซ็ป! ใช้ EntityManager แทนดีกว่า!
Spektakulatius

@ Code.IT ฉันเผยแพร่แนวคิด KISS นอกเหนือจากnativeQuery พารามิเตอร์คำอธิบายประกอบJPA ที่เพิ่มไม่ได้สำหรับการละเว้น
Grigory Kislin

@GKislin กว่าที่คุณต้องเปลี่ยนชื่อวิธีการเช่น findLimitOneByOtherObj นอกจากนี้คุณลืมเพิ่ม OrderBy ซึ่งนำไปสู่ผลลัพธ์ที่ไม่ถูกต้องหาก other_obj ไม่ซ้ำกัน มิฉะนั้นคำแถลงในคอลัมน์ที่ไม่ซ้ำกันควรเพียงพอโดยไม่มีขีด จำกัด
Spektakulatius

LIMIT คีย์เวิร์ดไม่จำศีล แต่ postgres / mysql
Acewin

5

หากชั้นเรียนของคุณ@RepositoryขยายJpaRepositoryคุณสามารถใช้ตัวอย่างด้านล่าง

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

getContent ส่งคืน a List<Transaction>.


จะเกิดอะไรขึ้นถ้าฉันมี 2 เงื่อนไขในแบบสอบถามเช่น transactionRepository.findByFirstNameAndLastName (firstname, lastname)? จะได้ผลไหม ฉันได้รับข้อยกเว้นนี้ org.springframework.data.mapping.PropertyReferenceException: ไม่พบคุณสมบัติที่สร้างสำหรับชนิด Board
Shailesh

4

นอกจากนี้ยังเป็นไปได้โดยใช้ @QueryHints ตัวอย่างการร้องใช้ org.eclipse.persistence.config.QueryHints # JDBC_MAX_ROWS

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

ฉันได้ทดสอบโค้ดนี้แล้ว แต่ใช้งานไม่ได้ ไม่มีข้อยกเว้น แต่ไม่มีผลลัพธ์ที่ถูกต้อง นอกจากนี้เอกสารยังมีความบางมากเกี่ยวกับ QueryHints ดูด้านล่าง docs.spring.io/spring-data/jpa/docs/1.7.1.RELEASE/reference/…
bogdan.rusu

IIRC ไม่มีการรับประกันว่าจะปฏิบัติตามคำแนะนำในการสืบค้น เป็นเพียงวิธีส่ง "คำแนะนำที่เป็นมิตร" ไปสู่การนำไปใช้งาน
Priidu Neemre

ฉันลองใช้@QueryHints({@QueryHint(name = org.hibernate.annotations.FETCH_SIZE, value = "1")})ใน Hibernate แต่นามแฝง :( ใช้ไม่ได้
Grigory Kislin

2
org.hibernate.annotations.FETCH_SIZE ขนาดการดึงข้อมูลไม่ จำกัด ไม่ใช่ผลลัพธ์สูงสุด Hiber cant
Zhuravskiy Vitaliy

4

new PageRequest(0,10)ใช้ไม่ได้กับ Spring เวอร์ชันใหม่กว่า (ฉันใช้อยู่2.2.1.RELEASE) โดยทั่วไปตัวสร้างมีพารามิเตอร์เพิ่มเติมเป็นSortประเภท ยิ่งไปกว่านั้นตัวสร้างprotectedนั้นคุณต้องใช้คลาสลูกตัวใดตัวหนึ่งหรือเรียกofวิธีการแบบคงที่:

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

คุณยังสามารถละเว้นการใช้Sortพารามิเตอร์และใช้การเรียงลำดับเริ่มต้นโดยปริยาย (เรียงลำดับตาม pk ฯลฯ ):

PageRequest.of(0, 10)

การประกาศฟังก์ชันของคุณควรเป็นดังนี้:

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

และฟังก์ชันจะเป็น:

userRepository.findByUsername("Abbas", PageRequest.of(0,10, Sort.sort(User.class).by(User::getLastName).ascending());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.