Search code examples
javaspringjpaenumsspring-data-jpa

What are some ways to pass an Enum value in a pure JPA @Query?


Let's say I want to set a record's column value as "RESOLVED". However, I want to have this value to picked up from an Enum. So the query stays the same regardless if somebody decides the "RESOLVED" to change to "RESOLVE" or something like that. In other words, the developer would not need to edit the JPA query with the new Enum value. Just wanted to know what are some ways to go about it, or if JPA doesn't allow that. I know queries are static but earlier I was able to pass an object inside a query to store the query result fields in it. So I wondered if one could do the same with Enums too.

This is my current strategy: To pass the "RESOLVE" as a @Param "status". However, I'd still like to know how to pass Enums as this feels like a work-around more than answering the question itself.

public interface UpdateStatusStandardDAO extends JpaRepository<DBTableName, Long>
{

    @Transactional
    @Modifying(clearAutomatically = true)
    @Query("UPDATE"
            + " TableName tn"
            + " SET"
            + " tn.status =:status"
            + " WHERE"
            + " tn.field1 =:field1"
            + " AND tn.field2 =:field2"
            + " AND tn.field3 =:field3")
    int updateStatus(@Param("status") String status, @Param("field1") Long field1,
                     @Param("field2") String field2, @Param("field3") String field3);

}

What I know: 1. @Transactional: for update/delete ops. Otherwise, I got org.springframework.dao.InvalidDataAccessApiUsageException. 2. @Modifying(clearAutomatically = true): Because the entity manager does not flush change automagically by default.

For simplicity, we consider field1 as primary key. It's type is Long (can be inferred also from the interface signature).

For pure reference, if none of the fields in the where clause is a key, then SQL workbench might reject your query if the SQL_SAFE_UPDATES options is set. That is because you can't update or delete records without specifying a key (example, primary key) in the where clause.


Solution

  • That's not possible because annotation attribute value must be constant and Enum is not a constant. But you can use java8 interface default method as a trick to solve it. The template code:

    public interface TheEntityJpaRepository extends JpaRepository<TheEntity, Long> {
      @Modifying(clearAutomatically = true)
      @Query("UPDATE TheEntity SET status = :status WHERE id = :value")
      int markToStatus(@Param("value") Long value, @Param("status") TheStatusEnum status);
    
      default int markAsResolved(Long value) {
        return markToStatus(value, TheStatusEnum.RESOLVED);
      }
    }
    
    @Entity
    public class YourEntity {
      ...
      @Enumerated(EnumType.STRING)
      private Status status;
      ...
    }
    
    public enum TheStatusEnum {
      RESOLVED,
      ...
    }
    

    But you should know that this way will exposed the markToStatus method.