基于类的投影与Spring Data JPA, CrudRepository



我们有一个使用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]

实体模型(AccountSalesHealth):

/* 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;
}

这里有一些关于基于类的预测的注释,似乎是适用的,这是相关的:

要使投影类与存储库接口协同工作,构造函数的参数名必须与的属性匹配根实体类。

我尝试了一些方法,但似乎没有任何效果:

  • Id以外的其他属性添加到Entity类

  • 重载DTO构造函数,使Id参数成为参数之一

  • 生成构造函数,而不是使用Lombok注释来指定构造函数参数的名称。

  • 在上述基础上,按第4节的要求添加equalshashCode

我错过了什么吗?

您可能错过了Spring Data JPA文档中的注释:

基于类的投影根本不能用于本机查询。作为一个您可以使用ResultSetMapping或Hibernate专用的ResultTransformer.

如建议的那样,您可以使用@NamedNativeQuery来定义本机查询,使用@SqlResultSetMapping来定义本机查询结果到DTO类的映射。要了解更多细节,请查看博客文章。

最新更新