Spring Data JPA сопоставляет собственный результат запроса с не-сущностью POJO

у меня есть метод хранилища данных Spring с собственным запросом

@Query(value = "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", nativeQuery = true)
    GroupDetails getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

и я хотел бы сопоставить результат с не-сущностью POJO GroupDetails.

возможно ли это, и если да, не могли бы вы привести пример ?

5 ответов


предполагая GroupDetails, как в ответе orid, вы пробовали 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")

и используйте следующее в интерфейсе репозитория:

GroupDetails getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

по данным Spring JPA документация, spring сначала попытается найти именованный запрос, соответствующий вашему имени метода, используя @NamedNativeQuery, @SqlResultSetMapping и @ConstructorResult вы должны быть в состоянии достичь, что поведение


Я думаю, что самый простой способ сделать это-использовать так называемые проекции. Он может сопоставлять результаты запросов с интерфейсами. Используя SqlResultSetMapping является непостоянным и делает ваш код уродливым :).

пример прямо из исходного кода spring data JPA:

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

вы также можете использовать этот метод для получения списка проекций.

проверьте эту запись spring data JPA docs для получения дополнительной информации о проекциях.

Примечание.: Не забудьте иметь свой User объект, определенный как обычный-поля из проектируемого интерфейса должны соответствовать полям в этом объекте. В противном случае отображение полей может быть нарушено (getFirstname() может возвращать значение фамилии и т. д.).


Если GroupDetails что-то вроде:

public class GroupDetails {

    int groupId;
    int userId;

    public GroupDetails(int groupId , int userId) {
        this.groupId = groupId;
        this.userId = userId;
    }

    // getters setters, etc.
}

следующее должно работать:

@Query(value = "SELECT new GroupDetails(gm.group_id, gm.user_id) 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")


Вы можете сделать что-то вроде

@NamedQuery(name="IssueDescriptor.findByIssueDescriptorId" ,

    query=" select new com.test.live.dto.IssuesDto (idc.id, dep.department, iss.issueName, 
               cat.issueCategory, idc.issueDescriptor, idc.description) 
            from Department dep 
            inner join dep.issues iss 
            inner join iss.category cat 
            inner join cat.issueDescriptor idc 
            where idc.id in(?1)")

и должен быть конструктор типа

public IssuesDto(long id, String department, String issueName, String issueCategory, String issueDescriptor,
            String description) {
        super();
        this.id = id;
        this.department = department;
        this.issueName = issueName;
        this.issueCategory = issueCategory;
        this.issueDescriptor = issueDescriptor;
        this.description = description;
    }

в моем компьютере, я получаю этот код работает.Это немного отличается от ответа Даймона.

@SqlResultSetMapping(
    name="groupDetailsMapping",
    classes={
        @ConstructorResult(
            targetClass=GroupDetails.class,
            columns={
                @ColumnResult(name="GROUP_ID",type=Integer.class),
                @ColumnResult(name="USER_ID",type=Integer.class)
            }
        )
    }
)

@NamedNativeQuery(name="User.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")