【问题标题】:spring boot data @query to DTO春季启动数据@query到DTO
【发布时间】:2019-04-18 17:14:03
【问题描述】:

我想将查询结果分配给 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;
    }
            
}

查询如下所示:

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

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

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]

【问题讨论】:

  • 有什么异常?
  • @MaciejKowalski 这是引发的异常。 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]
  • 您的查询似乎是本机查询(!= JPQL 或 HQL)。在这种情况下,请在注释中指定它,例如:@Query(value = "sql string ", nativeQuery = true)
  • 这个solution 可以在这种情况下正常工作。

标签: spring-boot spring-data-jpa jpql dto


【解决方案1】:

在我的项目中,我使用了 projections,如下所示:

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

结果投影到的接口:

public interface PeopleDTO {    
    String getName();
    Long getCount();    
}

投影界面中的字段必须与该实体中的字段匹配。否则字段映射可能会中断。

此外,如果您使用 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();

并创建interface MetricDTO 如下所示:

public interface MetricDTO {
    Integer getSum();    
    Long getCount();    
}

还要确保getSum()getCount() 的返回类型正确,这可能因数据库而异。

【讨论】:

    【解决方案2】:

    首先,您可以查看 Spring Data JPA 文档,您可以在此部分找到一些帮助:Class-based Projections (DTOs)

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

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

    @Value
    public class MetricDto {
    
        private int share;
        private int shareholder;
    
    }
    

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

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

    【讨论】:

    • 我尝试使用原生查询但没有用,仅使用 HQL,但您的建议对我有帮助
    【解决方案3】:
    Query query = sessionFactory.getCurrentSession()
                  .createNativeQuery(stringQuery).unwrap(org.hibernate.query.Query.class);
    
    ((NativeQueryImpl) query).setResultTransformer(new AliasToBeanResultTransformer(DtoClass.class));
    

    【讨论】:

    • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
    • 欢迎来到 Stack Overflow,感谢您提供答案。您能否编辑您的答案以包括对您的代码的解释?这将帮助未来的读者更好地理解正在发生的事情,尤其是那些不熟悉该语言并努力理解这些概念的社区成员。当已经有社区验证的答案时,这一点尤其重要。在什么条件下您的方法可能更受欢迎?您是否在利用新功能?
    猜你喜欢
    • 2016-03-27
    • 2020-08-19
    • 2019-07-21
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 2015-04-18
    • 2017-06-24
    • 2015-08-22
    相关资源
    最近更新 更多