使用Spring Data JPA和CrudRepository进行基于类的预测

m1m5dgzv  于 2023-01-20  发布在  Spring
关注(0)|答案(1)|浏览(137)

我们有一个使用DTO接口投影和CrudRepository的工作仓库实现。
我想把这些DTO接口转换成DTO类,因为我们需要它们在Redis缓存中是可序列化的。接口的Spring代理没有序列化/反序列化到数据存储所需的构造函数:

2023-01-18 15:13:28.949 ERROR 39286 [undedElastic-15] Error retrieving Mono value from redis cache: {}
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `com.sun.proxy.$Proxy173` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

不幸的是,当Spring尝试将查询结果转换为新的DTO时,我遇到了失败,并得到了如下错误:

at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ Handler com.clickbank.clientanalytics.controller.AccountSalesHealthController#grossSalesByAffiliate(JwtAuthenticationToken, AnalyticsRequest) [DispatcherHandler]

实体模型(会计销售健康):

/* Minimal table definition to use hibernate's CrudRepository */

@Data
@Entity
@Table(name = "mv_ca_account_sales_health")
public class AccountSalesHealth {
    @Id
    private Integer id;
}

现有存储库接口:

public interface AccountSalesHealthRepository extends CrudRepository<AccountSalesHealth, String> {
    @Query(
            value = "select vendor_master_account as vendorMasterAccount" +
                    "     , vendor" +
                    "     , affiliate" +
                    "     , bus_date         as busDate" +
                    "     , sum(sale_amount) as amount " +
                    "from mv_ca_account_sales_health " +
                    "where vendor_master_account = :vendorMasterAccount" +
                    "  and bus_date >= :start" +
                    "  and bus_date <= :end " +
                    "group by 1, 3, 2, 4",
            nativeQuery = true
    )
    Collection<AccountSalesHealthDto> getGrossSalesByAffiliate(@Param("vendorMasterAccount") String vendorMasterAccount, @Param("start") String start, @Param("end") String end);
...

旧的DTO类(此类有效):

public interface AccountSalesHealthDto {
    String getVendorMasterAccount();

    String getVendor();

    String getBusDate();

    String getAffiliate();

    String getItemNo();

    Double getAmount();

    Double getAffAmount();

    Double getNetAmount();

    Integer getSaleCount();
}

转换为类后:

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class AccountSalesHealthDto {

    private String vendorMasterAccount;

    private String vendor;

    private String busDate;

    private String affiliate;

    private String itemNo;

    private Double amount;

    private Double affAmount;

    private Double netAmount;

    private Integer saleCount;
}

有一些关于基于类的投影的注解here似乎是适用的,这一点非常重要:
对于与存储库接口协同工作的投影类,其构造函数的参数名必须与根实体类的属性匹配。
我试过几种方法,似乎都没有效果:

  • 将除Id之外的其他属性添加到Entity类
  • 重载DTO构造函数,使Id参数成为参数之一
  • 生成构造函数,而不是使用Lombok标注指定构造函数参数的名称。
  • 除上述内容外,添加第4节所述的equalshashCode

我错过什么了吗?

vaj7vani

vaj7vani1#

您可能错过了Spring Data JPA文档中的注解,其中写道:
基于类的投影根本不适用于本地查询。作为一种解决方案,您可以使用带有ResultSetMapping或Hibernate特定ResultTransformer的命名查询。
按照建议,可以使用@NamedNativeQuery定义本机查询,使用@SqlResultSetMapping定义本机查询结果到DTO类的Map。有关详细信息,请查看the blog post

相关问题