setMaxResults cho chú thích Spring-Data-JPA?


127

Tôi đang cố gắng kết hợp Spring-Data-JPA vào dự án của mình. Một điều làm tôi bối rối là làm cách nào để đạt được setMaxResults (n) bằng cách chú thích?

ví dụ: mã của tôi:

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

Tôi chỉ cần trả về one (and only one)Người dùng từ otherObj, nhưng tôi không thể tìm cách chú thích maxResults. Ai đó có thể cho tôi một gợi ý?

(mysql phàn nàn:

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

)

Tôi đã tìm thấy một liên kết: https://jira.springsource.org/browse/DATAJPA-147 , tôi đã thử nhưng không thành công. Có vẻ như không thể bây giờ? Tại sao một tính năng quan trọng như vậy không được tích hợp vào Spring-Data?

Nếu tôi thực hiện tính năng này theo cách thủ công:

public class UserRepositoryImpl implements UserRepository

Tôi phải thực hiện hàng tấn phương pháp được xác định trước CrudRepository, điều này sẽ rất tệ.

môi trường: spring-3.1, spring-data-jpa-1.0.3.RELEASE.jar, spring-data-commons-core-1.1.0.RELEASE.jar

Câu trả lời:


175

Kể từ Spring Data JPA 1.7.0 (tàu phát hành Evans).

Bạn có thể sử dụng các từ khóa vừa được giới thiệu TopFirstcho phép bạn xác định các phương thức truy vấn như thế này:

findTop10ByLastnameOrderByFirstnameAsc(String lastname);

Spring Data sẽ tự động giới hạn kết quả ở số bạn đã xác định (mặc định là 1 nếu bị bỏ qua). Lưu ý rằng thứ tự của các kết quả trở nên có liên quan ở đây (thông qua một OrderBymệnh đề như trong ví dụ hoặc bằng cách đưa một Sorttham số vào phương thức). Đọc thêm về điều đó trong bài đăng trên blog bao gồm các tính năng mới của tàu phát hành Spring Data Evans hoặc trong tài liệu .

Đối với các phiên bản trước

Để chỉ truy xuất các lát dữ liệu, Spring Data sử dụng tính trừu tượng phân trang đi kèm với Pageablegiao diện ở phía yêu cầu cũng như sự Pagetrừu tượng hóa ở phía kết quả của sự việc. Vì vậy, bạn có thể bắt đầu với

public interface UserRepository extends Repository<User, Long> {

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

và sử dụng nó như thế này:

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

Nếu bạn cần biết bối cảnh của kết quả (thực tế nó là trang nào? Đây có phải là trang đầu tiên không? Tổng cộng có bao nhiêu?), Sử dụng Pagelàm kiểu trả về:

public interface UserRepository extends Repository<User, Long> {

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

Mã khách hàng sau đó có thể làm một cái gì đó như thế này:

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

Không phải là chúng tôi sẽ kích hoạt phép chiếu đếm của truy vấn thực tế được thực thi trong trường hợp bạn sử dụng Pagelàm kiểu trả về vì chúng tôi cần tìm hiểu tổng số có bao nhiêu phần tử để tính siêu dữ liệu. Ngoài ra, hãy chắc chắn rằng bạn thực sự trang bị PageRequestthông tin sắp xếp để có kết quả ổn định. Nếu không, bạn có thể kích hoạt truy vấn hai lần và nhận được các kết quả khác nhau ngay cả khi không có dữ liệu thay đổi bên dưới.


14
Cảm ơn, nhưng tôi vẫn hy vọng vào một giải pháp 'dựa trên chú thích'. Bởi vì 'Trang / Hiển thị' quá mức cần thiết trong trường hợp này. Và khách hàng phải tạo một Trang có thể hiển thị / Trang để lấy kết quả 'một và chỉ một' ... Nó rất không thân thiện khi sử dụng. Và có vẻ như bạn phụ trách Spring-Data, tôi hy vọng bạn có thể xem xét thêm về vấn đề này: stackoverflow.com/questions/9276461/ . Bạn có thể xác nhận nếu đó là lỗi của Spring-Data không?
smallufo

1
+ điều này hoạt động, cảm ơn, nhưng một giải pháp dựa trên chú thích sẽ tốt hơn trong các phiên bản mới hơn
azerafati

1
một truy vấn đếm được thực hiện ở đây, điều này hoàn toàn không cần thiết nếu chúng ta muốn một truy vấn hạn chế.
azerafati

1
Không phải là nếu bạn sử dụng Listnhư kiểu trả về của phương thức.
Oliver Drotbohm

3
Tôi nghĩ, TopFirsttừ khóa không áp dụng cho các phương pháp sử dụng @Querychú thích? Chỉ những người sử dụng truy vấn dựa trên tên phương thức?
Ruslan Stelmachenko

106

Nếu bạn đang sử dụng Java 8 và Spring Data 1.7.0, bạn có thể sử dụng các phương thức mặc định nếu bạn muốn kết hợp một @Querychú thích với việc đặt kết quả tối đa:

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
có khả năng hữu ích cho một kết quả duy nhấtStream<User> ... {...} default Optional<User> ... { ...findAny() }
xenoterracide

28

Có một cách bạn có thể cung cấp tương đương với "một setMaxResults (n) bằng chú thích" như sau:

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

Điều này sẽ thực hiện các mẹo, khi một phân trang được gửi dưới dạng tham số. Chẳng hạn, để tìm nạp 10 bản ghi đầu tiên, bạn cần đặt phân trang theo giá trị này:

new PageRequest(0, 10)

Nếu bạn đang sử dụng Pagable thì trang trả về của nó <XYZ> không phải là Danh sách <XYZ>
Arundev

@Arundev sai - Listhoạt động hoàn hảo (và tránh một counttruy vấn không cần thiết như đã được đề cập trong một nhận xét trước đó )
Janaka Bandara

21

Sử dụng Spring Data Evans (1.7.0 ĐÁNG TIN CẬY)

bản phát hành mới của Spring Data JPA với một danh sách các mô-đun khác được gọi là Evans có tính năng sử dụng từ khóa Top20Firstđể giới hạn kết quả truy vấn,

vì vậy bây giờ bạn có thể viết

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

hoặc là

List<User> findTop20ByLastnameOrderByIdDesc(String lastname);

hoặc cho một kết quả duy nhất

List<User> findFirstByLastnameOrderByIdDesc(String lastname);

5
Tùy chọn <Người dùng> findFirstByLastnameOrderByIdDesc (Chuỗi họ);
krmanish007

Sau khi nhận được kết quả top20, làm cách nào tôi có được 20 kết quả tiếp theo khi tôi truy cập trang tiếp theo trên trang web bằng cách sử dụng phân trang?
kittu

@kittu, tất nhiên đó là một câu hỏi khác nhưng bạn cần phải vượt qua một Pageableđối tượng. xem tài liệu về mùa xuân
azerafati

tại sao họ thực hiện phương thức trả về một Danh sách chết tiệt nếu nó được chỉ định ĐẦU TIÊN ??
Vasile Surdu

13

Lựa chọn tốt nhất cho tôi là truy vấn gốc:

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

Không chắc chắn nếu giới hạn được hỗ trợ trong Hibernate: forum.hibernate.org/viewtopic.php?f=9&t=939314
Witold Kaczurba

2
Phá vỡ toàn bộ khái niệm! Thay vào đó hãy sử dụng EntityManager tốt hơn!
Spektakulatius

@ Code.IT Tôi tuyên truyền khái niệm KISS. Ngoài ra, nativeQuery tham số chú thích JPA được thêm vào không bỏ qua.
Grigory Kislin

@GKislin hơn bạn phải đổi tên phương thức của bạn như findLimitOneByOtherObj. Ngoài ra, bạn đã quên thêm OrderBy dẫn đến kết quả sai nếu other_obj không phải là duy nhất.
Mặt

Từ khóa LIMIT không phải là ngủ đông mà là postgres / mysql
Acewin

5

Nếu lớp học của bạn @Repositorymở rộng, JpaRepositorybạn có thể sử dụng ví dụ dưới đây.

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

getContent trả về a List<Transaction>.


Điều gì xảy ra nếu tôi có 2 điều kiện trong truy vấn như, giao dịchRep repository.findByFirstNameAndLastName (tên, họ)? nó sẽ làm việc chứ Tôi nhận được ngoại lệ này org.springframework.data.micking.PropertyReferenceException: Không tìm thấy thuộc tính nào cho loại bảng.
Shailesh

4

Nó cũng có thể sử dụng @QueryHints. Ví dụ dưới đây sử dụng org.eclipse.persistence.config.QueryHints # JDBC_MAX_lawS

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

Tôi đã kiểm tra mã này nhưng nó không hoạt động. Không có ngoại lệ, nhưng không có kết quả thích hợp hơn. Ngoài ra tài liệu rất mỏng về QueryH gợi ý. Xem bên dưới. docs.spring.io/spring-data/jpa/docs/1.7.1.RELEASE/reference/ory
bogdan.rusu

IIRC, không có gì đảm bảo rằng một gợi ý truy vấn sẽ được theo dõi. Đó chỉ là một cách để vượt qua "các khuyến nghị thân thiện" để thực hiện.
Priidu Neemre

Tôi dùng thử @QueryHints({@QueryHint(name = org.hibernate.annotations.FETCH_SIZE, value = "1")})trong Hibernate, nhưng bí danh :( không hoạt động
Grigory Kislin 7/12/2016

2
org.hibernate.annotations.FETCH_SIZE kích thước tìm nạp của nó, không giới hạn, không kết quả tối đa. Hiber cant
Zhuravskiy Vitaliy

4

new PageRequest(0,10)không hoạt động trong các phiên bản Spring mới hơn (tôi đang sử dụng 2.2.1.RELEASE). Về cơ bản, hàm tạo có một tham số bổ sung là Sortkiểu. Hơn nữa, hàm tạo protectednên bạn phải sử dụng một trong các lớp con của nó hoặc gọi ofphương thức tĩnh của nó :

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

Bạn cũng có thể bỏ qua việc sử dụng Sorttham số và ngầm định sử dụng sắp xếp mặc định (sắp xếp theo pk, v.v.):

PageRequest.of(0, 10)

Khai báo hàm của bạn phải giống như thế này:

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

và chức năng sẽ là:

userRepository.findByUsername("Abbas", PageRequest.of(0,10, Sort.sort(User.class).by(User::getLastName).ascending());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.