2010-03-29 4 views
7

È necessario assicurarsi che vengano restituiti solo i risultati degli ultimi 30 giorni per una query JPQL. Segue un esempio:Come eseguire un confronto di data/ora con la query 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();

Qui è l'errore che riceviamo:

<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 : ""

Aiuto!

+0

Che cos'è ts? Perché hai parentesi nella tua domanda? {...} – Rick

+0

Tentativo di utilizzare un "indicatore di data e ora di sintassi di escape JDBC" come indicato nei seguenti collegamenti. Sembra che il suggerimento di DataNucleus sia una soluzione molto migliore. 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

Dovresti aprire un bug contro OpenJPA per ottenere il codice ... o il documento corretto. – Rick

risposta

11

Quindi la query immessa non è JPQL (che è possibile vedere facendo riferimento alle specifiche JPA). Se vuoi confrontare un campo con una data, inserisci la data come parametro nella query

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

QUESTO NON E 'SQL.

+4

Questo è JPQL valido per la nostra implementazione JPA documentata qui: http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref.html#jpa_langref_lit utilizzando "Sintassi di escape JDBC". Dovresti considerare di provare una certa simpatia per le persone che cercano di iniziare con una nuova tecnologia. – Lightbeard

+2

Sì, hai ragione; Avevo dimenticato quanto fosse specifico per JPQL RDBMS. Si consiglia comunque di evitare tale sintassi poiché, secondo le specifiche JPA, si dipende dal driver JDBC che lo supporta e la query è in realtà molto più pulita con un parametro. – DataNucleus

9

La sintassi di escape JDBC potrebbe non essere supportata nella versione di OpenJPA che si sta utilizzando. La documentazione per l'ultima versione 1.2.x è qui: http://openjpa.apache.org/builds/1.2.2/apache-openjpa-1.2.2/docs/manual/manual.html#jpa_langref_lit.

La documentazione di cui in precedenza si riferisce ai documenti per OpenJPA 2.0.0 (l'ultima): http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref.html#jpa_langref_lit

Detto questo v'è alcuna ragione perché si vuole iniettare una stringa nella vostra JPQL? Che dire di qualcosa come il seguente frammento?

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

Preferirei utilizzare il parametro "now" invece della funzione JPQL "current_timestamp" come nel suggerimento DataNucleus, poiché la funzione restituisce l'ora sul server Database e new Date() restituisce l'ora sul contenitore Java. Se non sono la stessa macchina, ciò potrebbe causare errori se e quando gli orologi non si sincronizzano. –

+4

FYI, in JPQL, puoi usare un TypedQuery per evitare i cast. –