春季启动数据@query到DTO
Posted
技术标签:
【中文标题】春季启动数据@query到DTO【英文标题】:spring boot data @query to 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 可以在这种情况下正常工作。
【参考方案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,感谢您提供答案。您能否编辑您的答案以包括对您的代码的解释?这将帮助未来的读者更好地理解正在发生的事情,尤其是那些不熟悉该语言并努力理解这些概念的社区成员。当已经有社区验证的答案时,这一点尤其重要。在什么条件下您的方法可能更受欢迎?您是否在利用新功能?以上是关于春季启动数据@query到DTO的主要内容,如果未能解决你的问题,请参考以下文章