我们有一个使用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]
实体模型(Account tSalesHealth):
/* 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注释来指定构造函数参数的名称。
除此之外,添加equals
和hashCode
,如第4节所述。
我错过什么了吗?
您可能错过了Spring Data JPA留档中的注释:
基于类的投影根本不适用于本机查询。作为一种解决方法,您可以将命名查询与ResultSetMaps
或Hibernate特定的ResultTransformer
一起使用。
按照建议,您可以使用@NamedNativeQuery
定义本机查询,使用@SqlResultSetMaps
定义本机查询结果到DTO类的映射。有关更多详细信息,请查看博客文章。