从存储库接口检索列表到DTO列表类的最佳方法是什么

问题描述 投票:0回答:2

在DTO包中有类名DailyElectricity,它包含max,min,sum,getter和setter的平均值

public class DailyElectricity implements Serializable {

  private static final long serialVersionUID = 3605549122072628877L;


  private LocalDate date;

  private Long sum;

  private Double average;

  private Long min;

  private Long max;


}

有一个接口,它的工作是从数据库中获取数据

@RestResource(exported = false)
public interface HourlyElectricityRepository 
    extends PagingAndSortingRepository<HourlyElectricity,Long> {
  Page<HourlyElectricity> findAllByPanelIdOrderByReadingAtDesc(Long panelId,Pageable pageable);


  @Query("SELECT max(a.generatedElectricity), sum(a.generatedElectricity),min(a.generatedElectricity),max(a.generatedElectricity)  from HourlyElectricity a where DATE_FORMAT(reading_at,'%Y-%m-%d')=DATE_FORMAT(CURDATE()-1,'%Y-%m-%d') and  panel_id=:panelId")
  List<DailyElectricity> getStaticsDailyElectricity(@Param("panelId")Long panelId);

}

它编译没有任何异常,但当我调用它给它时

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.techtrial.dto.DailyElectricity]

它无法转换为dto类

spring-boot spring-data-jpa spring-data dto
2个回答
1
投票

问题是,spring无法弄清楚如何将查询结果转换为您期望的自定义​​对象DailyElectricity;为了使这种映射成为可能,您需要做两件事:

  1. 创建一个构造函数,以便您可以创建一个新对象并通过查询的每一行产生的值对其进行初始化: public DailyElectricity (Long max,Long sum,Long min,Double average){ this.sum=sum; this.average=average; this.min=min; this.max=max; }
  2. 然后在HourlyElectricityRepository中使用以下结构进行查询 @Query("SELECT new com.example.DailyElectricity( max(a.generatedElectricity), sum(a.generatedElectricity),min(a.generatedElectricity),avg(a.generatedElectricity)) from HourlyElectricity a where DATE_FORMAT(reading_at,'%Y-%m-%d')=DATE_FORMAT(CURDATE()-1,'%Y-%m-%d') and panel_id=:panelId") List<DailyElectricity> getStaticsDailyElectricity(@Param("panelId")Long panelId); 请注意我在查询中使用的包名(com.example.DailyElectricity),并确保在测试之前使用与您项目对应的正确包名。

0
投票

如果您使用的是class-based projections(DTO),则必须包含构造函数。尝试将其添加到您的DTO。

但最好使用Lombok来避免样板代码:

@Value
public class DailyElectricity {
  private LocalDate date;
  private Long sum;
  private Double average;
  private Long min;
  private Long max;
}

另一种方法是使用interface-based projections

public interface DailyElectricity {
  LocalDate getDate();
  Long getSum();
  Double getAverage();
  Long getMin();
  Long getMax();
}

IMO最好使用它们因为它们更简单并且它们具有一些优点(参见提供的手册)。

请注意,一种好的做法是在使用投影时在查询中使用别名。它们必须与投影中的对应字段名称/ getter匹配,例如:

"select max(a.generatedElectricity) as max, ..."

更新

不幸的是,在Spring Boot 2.0+中,基于类的投影不能像expected那样工作(与SB 1.5+不同 - 请参阅demo工作)。 在修复此错误之前,我们可以使用DTO constructor in the query

更新2

我错了 - 当我们使用基于类的投影和自定义查询时,无论Spring Boot的版本如何,我们都必须使用它的构造函数。

© www.soinside.com 2019 - 2024. All rights reserved.