如何将 sql 本机查询结果映射到 spring jpa 存储库中的 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, Integer>, JpaRepository<Stock, Long> {

   @Query(value = "SELECT new com.b2bwarehouse.Dto.RequestDto.StockDto.StockAkhirDto(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);
}

第二个是错误:

无法提取结果集; SQL [不适用];嵌套异常是 org.hibernate.exception.SQLGrammarException: 无法提取 ResultSet

下面是我的 DTO:

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

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

原文由 Ke Vin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

您可以使用适当的 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
   );
}

原文由 SternK 发布,翻译遵循 CC BY-SA 4.0 许可协议

我找到了一种不常见的方法,但是当我尝试使用 QueryDsl 来解决这个问题时,我发现了名为 “元组” 的数据类型,但如果你像我一样刚刚开始,我不会推荐 QueryDsl。让我们专注于我如何使用 “元组”

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

 @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<Tuple> findStockAkhirPerProductIn(@Param("warehouseCode") String warehouseCode, @Param("productCodes") Set<String> productCode);
}

然后在我的服务类中,因为它作为元组返回,我必须手动一一映射列,这是我的服务功能:

 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, String.class),
                    t.get(2, BigInteger.class)
                    ))
            .collect(Collectors.toList());

    return stockTotalDto;
}

列字段以 0 开头,这样我可以在存储库级别保持我的查询整洁。但我会接受 SternK 的回答作为公认的答案,因为这种方式也有效,如果有人需要这样的东西,我会在这里保留我的答案

原文由 Ke Vin 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题