How to compare LocalDateTime values in JPQL query?

424 Views Asked by At

It is necessary to select dataset using JPQL query with optional condition - comparing the field value (LocalDateTime type) with a user-specified parameter (also LocalDateTime type).

First I made a well working code:

return entityManager.createQuery(
    "SELECT new com.******.*******.*******.****.models.dto.SomeDto " +
    "(s.id, " +
    "s.userId) " +
    "s.persistDate) " +
    "FROM Some s WHERE s.userId = :userId 
    AND s.persistDate >= :userDateTime", SomeDTO.class)
    .setParameter("userId", userId)
    .setParameter("userDateTime", userDateTime)

This code works but there is one problem: this condition may exist or may not exist - dependent on app logic. Therefore, there is a need not to use injection using .setParameter (for this condition), but to form a string (which may be empty) depending on the logic and then add to the request:

String extraCondition = (userDateString.equals("false")) ? "" : 
    "AND s.persistDateTime >= " + userDateString;
return entityManager.createQuery(
    "SELECT new com.******.*******.*******.****.models.dto.SomeDto " +
    "(s.id, " +
    "s.userId) " +
    "s.persistDate) " +
    "FROM Some s WHERE s.userId = :userId " + extraCondition, SomeDTO.class)
    .setParameter("userId", userId)

But the problem is that no matter how I tried to format the userDateString variable, I get an Internal Server Error.I even tried using just a text string instead of variable (tried with different formatting):

String extraCondition = (userDateString.equals("false")) ? "" : 
    "AND s.persistDateTime >= 2023-01-27T23:30:50";

But the result is also bad - Internal Server Error.

I also tried using the .isAfter method instead of the ">=" operator, but that didn't help either.

How to inject LocalDateTime values comparing into query as String?

1

There are 1 best solutions below

4
jtahlborn On BEST ANSWER

even if the date string may or may not be necesssary, you can (and should!) still use parameter injection, not formatted values.

Basically, your code should look like this:

String queryStr = ....;
boolean someCondition = <expensive_test_here>;
if(someCondition) {
  queryStr += " AND s.persistDate >= :userDateTime";
}
Query q = em.createQuery(queryStr).setParameter("userId", userId);
if(someCondition) {
  q.setParameter("userDateTime", userDateTime);
}