50

Entity looks like this:

@Getter
@Setter
@Entity
public class Application {
@Id
private Long id;
@Enumerated(EnumType.STRING)
private ApplicationStatus status;
}

Code works this way:

public interface ApplicationRepository extends JpaRepository<Application, Long> {
@Query("SELECT app FROM #{#entityName} AS app WHERE app.status LIKE :status")
List<Application> find(@Param("status") ApplicationStatus status);

But the same snippet with nativeQuery - doesn't:

@Query(value = "SELECT app.* FROM application AS app WHERE app.status LIKE :status", nativeQuery = true)
List<Application> findNative(@Param("status") ApplicationStatus status);
}

And I don`t have any exception, just empty list.

How can I fix this? Is it possible to use enum with nativeQuery?

P.S I can pass String into method instead of ApplicationStatus but maybe there are another option?

Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
Tetiana Serediuk
  • 501
  • 1
  • 4
  • 5

6 Answers6

26

Following similar question with similar requirement and one of the answers pointing to Spring Expression Language (SpEL) you could use:

public interface ApplicationRepository extends JpaRepository<Application, Long> {
    @Query(nativeQuery = true, value = "SELECT app FROM #{#entityName} AS app WHERE app.status=:#{#status.name()}")
    List<Application> find(@Param("status") ApplicationStatus status);
}

Above important part is app.status=:#{#status.name()}

Ivar
  • 4,350
  • 2
  • 27
  • 29
  • 1
    Hi, thanks for your response, but how to handle situation when passing status as null ? – Vladimir Titov Feb 25 '22 at 08:04
  • I would suggest checking it within the curly braces of an expression `#{ ... }` e.g. `#status != null && ...` but I am not sure if expression engine can handle it – Ivar Feb 25 '22 at 13:19
  • To manage the null values, you need to add "?" : `app.status=:#{#status?.name()}` – Julien Kronegg Mar 20 '23 at 13:07
21

To extend on @Aivaras answer: If you want to use a list of statuses, the SpEL expression is slightly different - you need to do a projection:

public interface ApplicationRepository extends JpaRepository<Application, Long> {
    @Query(nativeQuery = true, value = "SELECT app FROM #{#entityName} AS app WHERE app.status in :#{#statuses.![name()]}")
    List<Application> find(@Param("statuses") List<ApplicationStatus> statuses);
}

Note the change of expression to

#{#statuses.![name()]}
Aserre
  • 4,916
  • 5
  • 33
  • 56
Alexey
  • 2,388
  • 1
  • 16
  • 32
  • If you don't mind, Could you explain the syntax as to how spEL works for collection.? – Arun Gowda Apr 01 '21 at 10:06
  • 1
    @ArunGowda it's called collection projection https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions-collection-projection . So out of collection of enums we create collection of strings – Alexey Apr 02 '21 at 12:38
4

I solved this issue using #{#paramName?.name()}

public interface ItemRepository extends JpaRepository<Item, Long> {
    @Query(value = "select * from items where type = :#{#type?.name()}", nativeQuery = true)
    List<Item> findByType(@Param("type") EnumType type);
}
 
public enum EnumType { NORMAL, LARGE };

Note: the "?" manages the case when the type parameter is null.

Julien Kronegg
  • 4,968
  • 1
  • 47
  • 60
Ousama
  • 2,176
  • 3
  • 21
  • 26
3

After a few days with this error, I was able to find the solution.

I did a lot of research and tested in many ways receiving as a parameter @Param("environment") environment: Environment:

 :#{#environment.TESTING}
 :#{#environment}
 :#{#environment.name()}
 CAST(:#{#environment.name()} as environment)

Solution in Kotlin

The key is in the query. You must to transform the value of the parameter to a String using .name() (or receive a String as a parameter) and cast that value of type String to the specific Enum that is needed. Because passing an object of type Enum directly in the query does not work.

Assuming the Enum in your database is defined as environment.

@Query(
        value = "SELECT some_routine(CAST(:#{#environmentNamedParam.name()} as environment))",
        nativeQuery = true
)
fun yourFunction(
        @Param("environmentNamedParam") environmentParam: Environment
) : Boolean

Differentiate between:

  • environmentNamedParam
  • environmentParam
  • environment

#spring #jpa #postgresql #kotlin

Braian Coronel
  • 22,105
  • 4
  • 57
  • 62
0

You could convert to string before passing the params.

johnlemon
  • 20,761
  • 42
  • 119
  • 178
-3

how about this?

public interface ApplicationRepository extends JpaRepository<Application, Long> {
List<Application> findByStatus(ApplicationStatus status);
David M.
  • 77
  • 1
  • 13