2010-03-29 12 views
7

Chúng tôi cần đảm bảo kết quả chỉ trong vòng 30 ngày qua được trả lại cho truy vấn JPQL. Một ví dụ sau:Làm cách nào để so sánh dấu thời gian với truy vấn JPA?

Date now = new Date(); 
Timestamp thirtyDaysAgo = new Timestamp(now.getTime() - 86400000*30); 

Query query = em.createQuery(
    "SELECT msg FROM Message msg "+ 
    "WHERE msg.targetTime < CURRENT_TIMESTAMP AND msg.targetTime > {ts, '"+thirtyDaysAgo+"'}"); 
List result = query.getResultList();

Đây là lỗi chúng tôi nhận được:

<openjpa-1.2.3-SNAPSHOT-r422266:907835 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: An error occurred while parsing the query filter 'SELECT msg FROM BroadcastMessage msg WHERE msg.targetTime < CURRENT_TIMESTAMP AND msg.targetTime > {ts, '2010-04-18 04:15:37.827'}'. Error message: org.apache.openjpa.kernel.jpql.TokenMgrError: Lexical error at line 1, column 217. Encountered: "{" (123), after : ""

Help!

+0

ts là gì? Tại sao bạn có dấu ngoặc trong truy vấn của mình? {...} – Rick

+0

Cố gắng sử dụng ký tự dấu thời gian "Cú pháp thoát JDBC" như được ghi trong các liên kết sau. Dường như đề xuất của DataNucleus là một giải pháp tốt hơn nhiều. http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref.html#jpa_langref_lit http://publib.boulder.ibm.com/infocenter/cscv/v10r1/topic/com.ibm.cloudscape.doc /rrefjdbc41784.html#rrefjdbc41784 – Lightbeard

+0

Bạn nên mở một lỗi chống lại OpenJPA để lấy mã ... hoặc doc đã được sửa. – Rick

Trả lời

11

Vì vậy, truy vấn bạn nhập không phải là JPQL (bạn có thể xem bằng cách tham khảo thông số JPA). Nếu bạn muốn so sánh một trường với một ngày thì bạn nhập ngày làm tham số vào truy vấn

msg.targetTime < CURRENT_TIMESTAMP AND msg.targetTime > :param 

NÀY KHÔNG PHẢI LÀ SQL.

+4

Đây là JPQL hợp lệ để thực hiện JPA của chúng tôi được ghi lại ở đây: http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref.html#jpa_langref_lit sử dụng "cú pháp thoát JDBC". Bạn nên xem xét có một số thông cảm cho những người đang cố gắng bắt đầu với một công nghệ mới. – Lightbeard

+2

Vâng, bạn nói đúng; Tôi đã quên cách cụ thể của RDBMS JPQL. Lời khuyên vẫn sẽ là tránh cú pháp như vậy, theo thông số JPA, bạn phụ thuộc vào trình điều khiển JDBC hỗ trợ nó, và truy vấn thực sự sạch hơn nhiều với tham số. – DataNucleus

9

Cú pháp thoát JDBC có thể không được hỗ trợ trong phiên bản OpenJPA mà bạn đang sử dụng. Tài liệu cho bản phát hành 1.2.x mới nhất có tại đây: http://openjpa.apache.org/builds/1.2.2/apache-openjpa-1.2.2/docs/manual/manual.html#jpa_langref_lit.

Các tài liệu đề cập trước đó đề cập đến các tài liệu cho OpenJPA 2.0.0 (mới nhất): http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref.html#jpa_langref_lit

Điều đó nói rằng có bất kỳ lý do tại sao bạn muốn tiêm một chuỗi thành JPQL của bạn? Điều gì về một cái gì đó giống như đoạn mã sau?

Date now = new Date(); 
Date thirtyDaysAgo = new Date(now.getTime() - (30 * MS_IN_DAY)); 

Query q = em.createQuery("Select m from Message m " 
    + "where m.targetTime < :now and m.targetTime > :thirtyDays"); 
q.setParameter("now", now); 
q.setParameter("thirtyDays", thirtyDaysAgo); 

List<Message> results = (List<Message>) q.getResultList(); 
+4

Tôi muốn sử dụng tham số "bây giờ" thay vì hàm JPQL "current_timestamp" như trong đề xuất DataNucleus, vì hàm trả về thời gian trên máy chủ Cơ sở dữ liệu và Date() mới trả về thời gian trên vùng chứa Java. Nếu chúng không phải là cùng một máy, điều này có thể dẫn đến lỗi nếu và khi đồng hồ không đồng bộ hóa. –

+4

FYI, trong JPQL, bạn có thể sử dụng một TypedQuery để tránh phôi. –