javahqljpqllocaldatetime

How to compare LocalDateTime values in JPQL query?


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?


Solution

  • 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);
    }