Spring Data JPA map the native query result to Non-Entity POJO
Solution 1:
I think the easiest way to do that is to use so called projection. It can map query results to interfaces. Using SqlResultSetMapping
is inconvienient and makes your code ugly :).
An example right from spring data JPA source code:
public interface UserRepository extends JpaRepository<User, Integer> {
@Query(value = "SELECT firstname, lastname FROM SD_User WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);
public static interface NameOnly {
String getFirstname();
String getLastname();
}
}
You can also use this method to get a list of projections.
Check out this spring data JPA docs entry for more info about projections.
Note 1:
Remember to have your User
entity defined as normal - the fields from projected interface must match fields in this entity. Otherwise field mapping might be broken (getFirstname()
might return value of last name et cetera).
Note 2:
If you use SELECT table.column ...
notation always define aliases matching names from entity. For example this code won't work properly (projection will return nulls for each getter):
@Query(value = "SELECT user.firstname, user.lastname FROM SD_User user WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);
But this works fine:
@Query(value = "SELECT user.firstname AS firstname, user.lastname AS lastname FROM SD_User user WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);
In case of more complex queries I'd rather use JdbcTemplate
with custom repository instead.
Solution 2:
Assuming GroupDetails as in orid's answer have you tried JPA 2.1 @ConstructorResult?
@SqlResultSetMapping(
name="groupDetailsMapping",
classes={
@ConstructorResult(
targetClass=GroupDetails.class,
columns={
@ColumnResult(name="GROUP_ID"),
@ColumnResult(name="USER_ID")
}
)
}
)
@NamedNativeQuery(name="getGroupDetails", query="SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", resultSetMapping="groupDetailsMapping")
and use following in repository interface:
GroupDetails getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);
According to Spring Data JPA documentation, spring will first try to find named query matching your method name - so by using @NamedNativeQuery
, @SqlResultSetMapping
and @ConstructorResult
you should be able to achieve that behaviour