微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在Spring JPA存储库中将SQL本机查询结果映射到DTO?

如何解决如何在Spring JPA存储库中将SQL本机查询结果映射到DTO?

您好,我想实现的是将sql本机查询结果映射映射到java spring jpa存储库中的DTO中,如何正确执行此操作?我尝试了几种代码,但没有用,这是我尝试过的:

第一次尝试:

@Repository
public interface StockRepository extends RevisionRepository<Stock,Long,Integer>,JpaRepository<Stock,Long> {
    
   @Query(value = "SELECT stock_akhir.product_id AS productId,stock_akhir.product_code AS productCode,SUM(stock_akhir.qty) as stockAkhir "
        + "FROM book_stock stock_akhir "
        + "where warehouse_code = (:warehouseCode) "
        + "AND product_code IN (:productCodes) "
        + "GROUP BY product_id,product_code,warehouse_id,warehouse_code",nativeQuery = true)
   List<StockAkhirDto> findStockAkhirPerProductIn(@Param("warehouseCode") String warehouseCode,@Param("productCodes") Set<String> productCode);
}

执行函数后,出现此错误

未找到能够从类型转换的转换器 [org.springframework.data.jpa.repository.query.AbstractJpaQuery $ TupleConverter $ TupleBackedMap] 键入[com.b2bwarehouse.Dto.RequestDto.StockDto.StockAkhirDto]

第二次尝试:

@Repository
public interface StockRepository extends RevisionRepository<Stock,Long> {
    
   @Query(value = "SELECT new com.b2bwarehouse.Dto.RequestDto.StockDto.StockAkhirDto(stock_akhir.product_id AS productId,SUM(stock_akhir.qty) as stockAkhir) "
      + "FROM book_stock stock_akhir "
      + "where warehouse_code = (:warehouseCode) "
      + "AND product_code IN (:productCodes) "
      + "GROUP BY product_id,@Param("productCodes") Set<String> productCode);
}

第二秒钟出现错误

无法提取ResultSet; sql [n / a];嵌套异常为 org.hibernate.exception.sqlGrammarException:无法提取 结果集

以下是我的DTO:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StockAkhirDto {
   private Long productId;
   private String productCode;
   private Integer stockAkhir;
}

我应该如何更正我的代码?那么,我可以将结果存入DTO吗?

解决方法

您可以使用适当的sql结果集映射定义以下命名的本机查询:

import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.ConstructorResult;
import javax.persistence.ColumnResult;

@Entity
@NamedNativeQuery(
    name = "find_stock_akhir_dto",query =
        "SELECT " + 
        "  stock_akhir.product_id AS productId," + 
        "  stock_akhir.product_code AS productCode," + 
        "  SUM(stock_akhir.qty) as stockAkhir " + 
        "FROM book_stock stock_akhir " + 
        "where warehouse_code = :warehouseCode " + 
        "  AND product_code IN :productCodes " + 
        "GROUP BY product_id,product_code,warehouse_id,warehouse_code",resultSetMapping = "stock_akhir_dto"
)
@SqlResultSetMapping(
    name = "stock_akhir_dto",classes = @ConstructorResult(
        targetClass = StockAkhirDto.class,columns = {
            @ColumnResult(name = "productId",type = Long.class),@ColumnResult(name = "productCode",type = String.class),@ColumnResult(name = "stockAkhir",type = Integer.class)
        }
    )
)
public class SomeEntity
{
}

然后使用它:

@Repository
public interface StockRepository extends RevisionRepository<Stock,Long,Integer>,JpaRepository<Stock,Long> {

   @Query(name = "find_stock_akhir_dto",nativeQuery = true)
   List<StockAkhirDto> findStockAkhirPerProductIn(
      @Param("warehouseCode") String warehouseCode,@Param("productCodes") Set<String> productCode
   );
}
,

第二个变体非常接近。您只需要删除构造函数表达式的别名:

new com.b2bwarehouse.Dto.RequestDto.StockDto.StockAkhirDto(
    stock_akhir.product_id,stock_akhir.product_code,SUM(stock_akhir.qty)
)

应该工作。

,

我找到了一种不常见的方法,但是当我尝试使用QueryDsl解决此问题时,我发现了称为“元组” 的数据类型,但是如果您只是一个人,我就不建议使用QueryDsl像我一样开始。让我们专注于我如何使用“元组”

我将返回类型更改为元组,这是我的存储库的外观:

@Repository
public interface StockRepository extends RevisionRepository<Stock,Long> {
    
   @Query(value = "SELECT stock_akhir.product_id AS productId,stock_akhir.product_code AS productCode,SUM(stock_akhir.qty) as stockAkhir "
        + "FROM book_stock stock_akhir "
        + "where warehouse_code = (:warehouseCode) "
        + "AND product_code IN (:productCodes) "
        + "GROUP BY product_id,nativeQuery = true)
   List<Tuple> findStockAkhirPerProductIn(@Param("warehouseCode") String warehouseCode,@Param("productCodes") Set<String> productCode);
}

然后在我的服务类中,由于它以Tuple的形式返回,因此我必须手动一一映射该列,这是我的服务函数:

public List<StockTotalResponseDto> findStocktotal() {
    List<Tuple> stockTotalTuples = stockRepository.findStocktotal();
    
    List<StockTotalResponseDto> stockTotalDto = stockTotalTuples.stream()
            .map(t -> new StockTotalResponseDto(
                    t.get(0,String.class),t.get(1,t.get(2,BigInteger.class)
                    ))
            .collect(Collectors.toList());
    
    return stockTotalDto;
}

列字段以0开头,这样我就可以在存储库级别保持查询整洁。但是我会接受SternK答案作为接受的答案,因为那样也行得通,如果有人需要这样的东西,我会将答案保留在这里

,

创建标准的原生@Query

@Query(value = "select id,age,name FROM Person WHERE age=?1",nativeQuery=true)
List<PersonView> getPersonsByAge(int age);

和一个界面

public interface PersonView {
    Long getId();
    Integer getAge();
    String getName();
}

列按顺序匹配(而不是按名称)。 这样,您就有了一个原生查询,没有实体,也没有太多的样板代码(也就是很多注释)。

但是,结果视图(Jdk 代理等)的访问速度非常慢,我有一些代码对流进行了一些分组,结果是 10 倍!!比标准 DTO/Pojos 慢! 所以最后,我不再使用 nativeQuery,但是:

SELECT new com.my_project.myDTO(p.id,p.age,p.name) .....

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。