2012-02-25 12 views
34

Sử dụng JPA 2 với triển khai EclipseLink.So sánh các đối tượng ngày trong API tiêu chí JPA

Tôi đang cố tạo một truy vấn động sẽ mang lại cho tôi một số bản ghi được lưu giữ sau một ngày cụ thể.

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<Event> criteria = builder.createQuery(Event.class); 
Root<Event> root = criteria.from(Event.class); 
criteria.select(root); 
criteria.distinct(true); 
List<Predicate> predicates = new ArrayList<Predicate>(); 
//... 
if (dateLimit != null){ 
    ParameterExpression<Date> param = builder.parameter(Date.class, "dateLimit"); 
    predicates.add(builder.lessThanOrEqualTo(root.get("dateCreated"), param)); 
} 

lessThanOrEqualTo()le() là hai phương pháp duy nhất trong API mà trông giống như có thể giúp tôi trong trường hợp này. Cảnh báo này được thực hiện bởi nhật thực mặc dù:

Bound mismatch: The generic method lessThanOrEqualTo(Expression<? extends Y>, Expression<? extends Y>) 
of type CriteriaBuilder is not applicable for the arguments (Path<Object>, ParameterExpression<Date>). 
The inferred type Object is not a valid substitute for the bounded parameter 
<Y extends Comparable<? super Y>> 

Tôi có thể tưởng tượng rằng tôi không sử dụng đúng phương pháp cho vấn đề này nhưng tôi không thể tìm thấy bất kỳ đâu mẹo hoặc giải pháp có thể.

Trả lời

58

Vấn đề là với API dựa trên chuỗi, nó không thể suy ra loại cho giá trị kết quả của get -Operation. Điều này được giải thích ví dụ trong Javadoc for Path.

Nếu bạn sử dụng

predicates.add(builder.lessThanOrEqualTo(root.<Date>get("dateCreated"), param)); 

thay vào đó, nó sẽ làm việc tốt, vì nó có thể tìm ra các kiểu trả về từ các đối số kiểu và sẽ tìm ra rằng nó có thể so sánh. Lưu ý, việc sử dụng lời gọi phương thức được tham số hóa root.<Date>get(...) (xem, ví dụ: When is a parameterized method call useful?).

Giải pháp khác (theo ý kiến ​​của tôi tốt hơn) là sử dụng API dựa trên metamodel thay vì API dựa trên chuỗi meta. Một ví dụ đơn giản về metamodel kinh điển được đưa ra ví dụ here. Nếu bạn có nhiều thời gian để đầu tư, đây là một bài viết hay về metamodel tĩnh: Dynamic, typesafe queries in JPA 2.0

+1

NetBeans 8.2 vẫn cảnh báo với tiêu chí. Tôi không biết tại sao. 'builder.greaterThanOrEqualsTo (root.get (Some_.date), date)' <> 'builder.greaterThanOrEqualsTo (root. get (Some_.date), date)' –

+0

@Jin Kwon: Đảm bảo nhập 'javax.persistence .criteria.Predicate', không phải 'java.util.function.Predicate'. Điều đó cố định nó cho tôi :) – Hank

+0

Không phải là một vấn đề nhập khẩu xấu, đó là một lỗi, một lỗi rất cũ. để giải quyết sự cố, bạn phải khai báo nó dưới dạng biến và sử dụng nó làm tham số: 'Đường dẫn đường dẫn = root.get (.....); builder.greaterThan (đường dẫn, ngày tháng); ' – FiruzzZ

12

Bạn cần sử dụng metamodel được tạo để truy cập các thuộc tính là một cách thực sự an toàn. Nếu bạn sử dụng Strings để đề cập đến thuộc tính của bạn, loại chỉ có thể được suy ra từ các loại generic rõ ràng sử dụng khi gọi phương pháp, hoặc bởi một loại băng bột hoặc bởi những suy luận kiểu tự động thực hiện bởi trình biên dịch:

Path<Date> dateCreatedPath = root.get("dateCreated"); 
predicates.add(builder.lessThanOrEqualTo(dateCreatedPath, dateLimit)); 
1

Tôi đã nhận được một lỗi tương tự nhưng với cú pháp predicates.add(cb.greaterThan(article.get(Article_.created), since)); và tìm thấy trang này. Nguyên nhân của tôi, hóa ra là tôi đã nâng cấp dự án của mình từ Java 1.7 lên 1.8, và trong quá trình này cũng đã cấu hình Maven để biên dịch cho Java 1.8. Tôi chỉ đơn giản là phải thay đổi Maven biên dịch trở lại 1.7, trong khi vẫn giữ phần còn lại của dự án ở 1.8, để sửa lỗi.