spring 启动数据 @query 到 DTO

bti*_*sae 6 dto jpql spring-data-jpa spring-boot

我想将查询结果分配给 DTO 对象。DTO 看起来像这样:

@Getter
@Setter
@NoArgsConstructor
public class Metric {
    private int share;
    private int shareholder;

    public Metric(int share, int shareholder) {
        this.share = share;
        this.shareholder = shareholder;
    }
            
}
Run Code Online (Sandbox Code Playgroud)

查询如下所示:

@RepositoryRestResource(collectionResourceRel = "shareholders", path = "shareholders")
public interface ShareholderRepository extends PagingAndSortingRepository<Shareholder, Integer> {
    @Query(value = "SELECT new com.company.shareholders.sh.Metric(SUM(s.no_of_shares),COUNT(*)) FROM shareholders s WHERE s.attend=true")
    Metric getMetrics();
}
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用,因为我遇到了以下异常:

Caused by:org.hibernate.QueryException: could not resolve property: no_of_shares of:com.company.shareholders.sh.Shareholder[SELECT new com.company.shareholders.sh.Metric(SUM(s.no_of_shares),COUNT(*)) FROM com.company.shareholders.sh.Shareholder s WHERE s.attend=true]
Run Code Online (Sandbox Code Playgroud)

Tha*_*thu 6

在我的项目中,我使用了如下所示的投影

@Repository
public interface PeopleRepository extends JpaRepository<People, Long> {
    
    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
                   "FROM people p INNER JOIN dream_people dp " +
                   "ON p.id = dp.people_id " +
                   "WHERE p.user_id = :userId " +
                   "GROUP BY dp.people_id " +
                   "ORDER BY p.name", nativeQuery = true)
    List<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId);
    
    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
                   "FROM people p INNER JOIN dream_people dp " +
                   "ON p.id = dp.people_id " +
                   "WHERE p.user_id = :userId " +
                   "GROUP BY dp.people_id " +
                   "ORDER BY p.name", nativeQuery = true)
    Page<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId, Pageable pageable);
    
    }
Run Code Online (Sandbox Code Playgroud)

结果投影到的接口:

public interface PeopleDTO {    
    String getName();
    Long getCount();    
}
Run Code Online (Sandbox Code Playgroud)

来自投影接口的字段必须与该实体中的字段匹配。否则字段映射可能会中断。

此外,如果您使用SELECT table.column表示法,请始终定义与实体名称匹配的别名,如示例所示。

在您的情况下,更改@Query如下所示:

@Query(value = "SELECT new " + 
               "SUM(s.no_of_shares) AS sum,COUNT(*) AS count FROM " +
               "shareholders s WHERE s.attend=true", nativeQuery = true)
MetricDTO getMetrics();
Run Code Online (Sandbox Code Playgroud)

并创建interface MetricDTO 如下所示:

public interface MetricDTO {
    Integer getSum();    
    Long getCount();    
}
Run Code Online (Sandbox Code Playgroud)

另外,还要确保的返回类型getSum()getCount()正确这可能会因不是基于数据库。


Gui*_*sta 4

首先,您可以查看 Spring Data JPA 文档,您可以在本节中找到一些帮助:基于类的投影(DTO)

还有一个标题为避免投影 DTO 的样板代码的段落,其中建议您使用 Lombok 的@Value注释来生成不可变的 DTO。这与 Lombok 的注释类似@Data,但不可变。

如果您将其应用到您的示例中,源代码将如下所示:

@Value
public class MetricDto {

    private int share;
    private int shareholder;

}
Run Code Online (Sandbox Code Playgroud)

然后,由于您的查询是 NativeQuery,因此在 Spring Data Repository 中指定它。您可以在文档中找到帮助:本机查询。你将需要类似的东西:

@Query(value = "SELECT new 
   com.company.shareholders.sh.MetricDto(SUM(s.no_of_shares),COUNT(*)) FROM 
   shareholders s WHERE s.attend=true", nativeQuery = true)
   MetricDto getMetrics();
Run Code Online (Sandbox Code Playgroud)