I'm developing a Spring Boot application with Spring Data JPA. I'm using a custom JPQL query to group by some field and get the count. Following is my repository method.
@Query(value = "select count(v) as cnt, v.answer from Survey v group by v.answer")
public List<?> findSurveyCount();
It's working and result is obtained as follows:
[
[1, "a1"],
[2, "a2"]
]
I would like to get something like this:
[
{ "cnt":1, "answer":"a1" },
{ "cnt":2, "answer":"a2" }
]
How can I achieve this?
I do not like java type names in query strings and handle it with a specific constructor. Spring JPA implicitly calls constructor with query result in HashMap parameter:
Code needs Lombok for resolving @Getter
Solution for JPQL queries
This is supported for JPQL queries within the JPA specification.
Important notes
MyBean
and it is in packagecom.path.to
, the fully-qualified path to the bean will becom.path.to.MyBean
. Simply providingMyBean
will not work (unless the bean class is in the default package).new
keyword.SELECT new com.path.to.MyBean(...)
will work, whereasSELECT com.path.to.MyBean(...)
will not.@Query("SELECT ...")
, or@Query(value = "SELECT ...")
, or@Query(value = "SELECT ...", nativeQuery = false)
will work, whereas@Query(value = "SELECT ...", nativeQuery = true)
will not work. This is because native queries are passed without modifications to the JPA provider, and are executed against the underlying RDBMS as such. Sincenew
andcom.path.to.MyBean
are not valid SQL keywords, the RDBMS then throws an exception.Solution for native queries
As noted above, the
new ...
syntax is a JPA-supported mechanism and works with all JPA providers. However, if the query itself is not a JPA query, that is, it is a native query, thenew ...
syntax will not work as the query is passed on directly to the underlying RDBMS, which does not understand thenew
keyword since it is not part of the SQL standard.In situations like these, bean classes need to be replaced with Spring Data Projection interfaces.
Use the SQL
AS
keyword to map result fields to projection properties for unambiguous mapping.define a custom pojo class say sureveyQueryAnalytics and store the query returned value in your custom pojo class
I know this is an old question and it has already been answered, but here's another approach:
This SQL query return List< Object[] > would.
You can do it this way:
Using interfaces you can get simpler code. No need to create and manually call constructors
Step 1: Declare intefrace with the required fields:
Step 2: Select columns with same name as getter in interface and return intefrace from repository method: