a

Câu hỏi Hibernate Chọn Top và Bottom n hàng với tiêu chí


Giả sử tôi có hai bảng, Sách và Bài đánh giá. Bài đánh giá có một cột, sao, có thể có giá trị từ 1 đến 5. Sách có thể có nhiều Bài đánh giá.

Làm cách nào để chọn tất cả các sách như vậy chỉ có 3 bài đánh giá trên cùng và dưới cùng cho mỗi cuốn sách được trả lại (thay vì tất cả các bài đánh giá) bằng cách sử dụng API tiêu chí?

Nếu API tiêu chí không có khả năng, tôi sẽ đưa ra các đề xuất khác như HQL, SQL, v.v.


18
2017-07-31 05:08


gốc




Các câu trả lời:


Bạn luôn có thể đặt thứ tự asc / desc và sau đó giới hạn kết quả.

ví dụ:

criteria.addOrder(Order.desc("id"));
criteria.setMaxResults(1);

Không chắc nơi nó đứng về hiệu quả. Tôi giả định rằng nó đang lọc sau khi thực tế là Select * đã bị sa thải?


18
2018-04-19 13:46





Hãy thử điều này và cho tôi biết nếu nó hoạt động cho bạn:

  // you should have the DAO class containing this queries 
  // extend HibernateDaoSupport

  List<Tag> topList = getSession().createQuery("FROM Reviews r WHERE r.book = " 
          + book + " ORDER BY r.stars asc").setMaxResults(3).list();

  List<Tag> bottomList = getSession().createQuery("FROM Reviews r WHERE r.book = " 
          + book + " ORDER BY r.stars desc").setMaxResults(3).list();

13
2017-08-08 13:23



Cảm ơn. Có, tôi đã kết thúc thêm một cái gì đó như thế này để xem xét của tôi DAO nhưng tôi thích API tiêu chí vì vậy tôi sử dụng đó. Vấn đề là, tôi đang truy vấn tất cả các Sách phù hợp với một tiêu chí nhất định và mỗi Sách cần có các Đánh giá trên cùng và dưới cùng của nó. Sẽ rất không hiệu quả và khó xử khi chạy truy vấn đó sau đó tự đi qua từng Đánh giá, chạy hai truy vấn này và tinh chỉnh phản hồi. Tôi đã giải quyết trên một giải pháp khác. - SingleShot


Trả lời câu hỏi của riêng tôi ...

Tôi thực sự ngạc nhiên về sự khó khăn này. Tất cả các giải pháp liên quan đến truy vấn Sách và từng Sách có danh sách các kết quả Đánh giá trên cùng và dưới cùng trong N truy vấn trên mỗi Sách trên một số cơ sở dữ liệu và đặc biệt là MySql yêu cầu 3N. Tất nhiên, ai đó có thể tìm ra cách thông minh xung quanh điều này, nhưng tôi đang chơi với mã, SQL thô, nghiên cứu những gì người khác đã làm, giới hạn cơ sở dữ liệu, v.v. luôn xuất hiện trở lại.

Vì vậy ... tôi đã kết thúc vấn đề xung quanh. Thay vì tính toán Đánh giá trên cùng và dưới cùng bất cứ khi nào tôi truy vấn Sách (đây là truy vấn rất thường xuyên - Sách FYI / Bài đánh giá là mục đích ví dụ - tên miền thực tế khác nhau) Tôi tính toán trên cùng / dưới cùng mỗi khi có Đánh giá mới. Điều này thay đổi gửi Đánh giá từ một "truy vấn" vào ba truy vấn, nhưng việc gửi Đánh giá là khá không thường xuyên so với truy vấn Sách.

Để làm điều này, tôi đã thêm hai thuộc tính mới vào Book, topReviews và bottomReviews và ánh xạ chúng thành một danh sách một-nhiều trên Đánh giá. Sau đó, tôi đã cập nhật mã để lưu Đánh giá mới để truy vấn Đánh giá trên cùng và dưới cùng cho Sách được đề cập (2 truy vấn), đặt thuộc tính Đánh giá trên cùng / dưới cùng trên Sách (ghi đè trước đó) và lưu Sách. Mọi truy vấn Sách bây giờ sẽ trả về các đánh giá trên cùng và dưới cùng "được lưu trong bộ nhớ cache" này. Tôi vẫn có một tài sản "đánh giá" lười biếng sẽ có tất cả các đánh giá (không chỉ trên cùng / dưới cùng) nếu muốn - một ánh xạ một-nhiều khác.

Tôi mở cho các khuyến nghị khác. Hầu hết các câu trả lời ở đây là trong công viên bóng nhưng bỏ lỡ vấn đề hoặc sẽ không hoạt động do hạn chế về cơ sở dữ liệu hoặc yêu cầu quá nhiều truy vấn.


5
2017-08-08 20:44





Điều này thường sẽ được thực hiện với một cái gì đó giống như một công đoàn, mà bạn không thể làm trong HQL.

Tuy nhiên, bạn có thể thực hiện điều này trong HQL

WHERE id in ([SELECT top 3]) or id in ([SELECT bottom 3])

Tôi không có một cách để kiểm tra điều này, nhưng điều này có thể làm việc quá.

DetachedCriteria topN = [ your criteria ] 
DetachedCriteria bottomN = [ your criteria ] 

session.createCriteria(..._
    .add( Property.or(Property.forName("id").in(topN),Property.forName("id").in(bottomN) )
    .list();

1
2017-08-02 17:22



Cảm ơn. Tôi chắc rằng tôi không thể sử dụng đề xuất Tiêu chí của bạn vì DetachedCriteria không có phương thức setMaxResults (), mà tôi cần để giới hạn kết quả ở trên cùng / dưới cùng 3 (có thực sự là một yêu cầu trong trang JIRA của Hibernate để thêm vào tính năng này). Tuy nhiên, tôi sẽ thử HQL của bạn. - SingleShot
Nó xuất hiện những gì bạn đề nghị, và nói chung, những gì tôi muốn, là không thể với Tiêu chí, HQL, và như xa như tôi có thể nói ngay cả SQL (ít nhất là trên MySQL). Tôi có thể lật ngược vấn đề này và thực hiện một số xử lý trước khi đánh giá được lưu để các đánh giá trên cùng / dưới cùng cho mỗi cuốn sách được lưu trong một bảng đặc biệt. - SingleShot
Tôi khá chắc chắn rằng nó có thể trong MySQL, đăng truy vấn của bạn và tôi sẽ lấy al ook - dfb
MySQL không hỗ trợ subselects với giới hạn :-( - SingleShot
Gah, bắt tốt. Hầu hết các phương ngữ khác hỗ trợ điều này, tôi đã thử nó trong MSSQL. Một giải pháp khó chịu sẽ là bảng tạm thời. Đăng bài nếu bạn tìm thấy điều gì đó tốt hơn - dfb


Tôi không nghĩ rằng bạn có thể làm những gì bạn muốn bằng cách sử dụng một truy vấn duy nhất. Bạn chắc chắn có thể làm điều đó trong hai, tuy nhiên (sử dụng EJBQL với các tham số được đặt tên):

SELECT r FROM Reviews r WHERE r.book = :book ORDER BY r.stars ASC LIMIT 3;
SELECT r FROM Reviews r WHERE r.book = :book ORDER BY r.stars DESC LIMIT 3;

Và tất nhiên bạn có thể viết một phương thức trợ giúp đơn giản để thực hiện cả hai cuộc gọi này và thu thập kết quả vào bất kỳ cấu trúc dữ liệu nào bạn thích.


0
2017-07-31 05:18



LIMIT là RDMS cụ thể. Không sử dụng nó. Sử dụng setMaxResults. - Alex Gitelman
@Alex - LIMIT cũng là một phần của Thông số EJBQL. - aroth
bạn đúng rồi. Tôi không bao giờ sử dụng nó. Tuy nhiên, anh ta muốn truy vấn tiêu chí. - Alex Gitelman
Dường như câu hỏi này hơi khác một chút. Anh ấy muốn sách không được đánh giá. Tôi rút lại câu trả lời của mình lúc này vì tôi không tin rằng tôi đang trả lời đúng câu hỏi. - Alex Gitelman
@ Alex - Điểm tốt, anh ấy muốn "chọn tất cả các sách như vậy mà chỉ có 3 bài đánh giá trên cùng và dưới cùng cho mỗi cuốn sách được trả về", điều mà tôi không nghĩ là có thể trực tiếp. Thông thường, khi tôi muốn một thực thể cung cấp bộ lọc tùy chỉnh "tự động" của một bộ sưu tập của một số pháp nhân khác, tôi thêm @Transient phương thức để thực thể đầu tiên thực hiện lọc mong muốn trên bộ sưu tập sao lưu và sau đó trả về kết quả (trong một cá thể bộ sưu tập mới). - aroth


Làm thế nào về việc lập bản đồ cho Đánh giá và Đặt làm nhiều người và sau đó trong bộ sưu tập đánh giá của Sách, chỉ định: order-by = "rating desc" và lazy = "true"

Giả sử với phương thức tìm nạp lười, dữ liệu sẽ được tìm nạp chỉ khi đối tượng được lấy từ bộ sưu tập, nhưng tôi không chắc chắn về điều này. Để xác nhận, bạn có thể bật ghi nhật ký SQL Hibernate và theo dõi các truy vấn nào đã được thực hiện trong thời gian chạy.


0
2017-08-04 12:58



Tôi cần cả hai đánh giá trên và dưới, vì vậy điều này không hoàn toàn hoạt động. Xem câu trả lời của tôi. Cảm ơn! - SingleShot


Hai truy vấn HQL sử dụng org.springframework.data.domain.Pageable như:

trước đó trong dịch vụ lớp giữa, bạn tạo ra repo có thể xem và gọi lại:

Pageable pageableTop = new PageRequest(0, 3, Direction.ASC, "yourFieldToSortBy");
yourRepository.findTopOrderByYourEntity(pageableTop);

Pageable pageableBottom = new PageRequest(0, 3, Direction.DESC, "yourFieldToSortBy");
yourRepository.findTopOrderByYourEntity(pageableBottom);

repo:

public interface YourRepository extends CrudRepository<YourEntity, String> {

    @Query("FROM YourEntity")
    List<YourEntity> findTopOrderByYourEntity(Pageable pageable);
}

0
2017-08-04 22:13