2010-03-29 13 views
7

Necesitamos asegurarnos de que solo se devuelven resultados en los últimos 30 días para una consulta JPQL. Un ejemplo es el siguiente:¿Cómo hacer una comparación de marca de tiempo con la consulta 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();

Aquí está el error que recibimos:

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

Ayuda!

+0

¿Qué es ts? ¿Por qué tienes paréntesis en tu consulta? {...} – Rick

+0

Intentando utilizar un literal de marca de tiempo "sintaxis de escape JDBC" como se documenta en los siguientes enlaces. Parece que la sugerencia de DataNucleus es una solución mucho mejor. 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

Debería abrir un error en OpenJPA para obtener el código ... o el documento corregido. – Rick

Respuesta

11

Por lo tanto, la consulta que ingrese no es JPQL (que puede ver consultando las especificaciones de JPA). Si desea comparar un campo con una fecha, ingrese la fecha como parámetro en la consulta

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

ESTO NO ES SQL.

+4

Esto es válido para nuestra implementación de JPA documentada aquí: http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref.html#jpa_langref_lit usando "sintaxis de escape JDBC". Debería considerar sentir simpatía por las personas que intentan comenzar una nueva tecnología. – Lightbeard

+2

Sí, tienes razón; Olvidé que tan específico para RDBMS es JPQL. Aconsejar sería evitar dicha sintaxis ya que, según la especificación JPA, depende del controlador JDBC que la soporta, y la consulta es mucho más clara con un parámetro. – DataNucleus

9

La sintaxis de escape JDBC puede no ser compatible con la versión de OpenJPA que está utilizando. La documentación para la última versión 1.2.x está aquí: http://openjpa.apache.org/builds/1.2.2/apache-openjpa-1.2.2/docs/manual/manual.html#jpa_langref_lit.

La documentación mencionada anteriormente se refiere a los documentos de OpenJPA 2.0.0 (última): http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref.html#jpa_langref_lit

Dicho esto ¿hay alguna razón por la que desea inyectar una cadena en su JPQL? ¿Qué tal algo como el siguiente fragmento?

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

Preferiría usar el parámetro "ahora" en lugar de la función JPQL "current_timestamp" como en la sugerencia de DataNucleus, ya que la función devuelve la hora en el servidor de base de datos y nueva fecha() devuelve la hora en el contenedor de Java. Si no son la misma máquina, esto podría generar errores siempre y cuando los relojes no se sincronicen. –

+4

FYI, en JPQL, puede usar TypedQuery para evitar lanzamientos. –

Cuestiones relacionadas