提问者:小点点

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]

实体模型(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注释来指定构造函数参数的名称。

    除此之外,添加equalshashCode,如第4节所述。

    我错过什么了吗?


  • 共1个答案

    匿名用户

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

    基于类的投影根本不适用于本机查询。作为一种解决方法,您可以将命名查询与ResultSetMaps或Hibernate特定的ResultTransformer一起使用。

    按照建议,您可以使用@NamedNativeQuery定义本机查询,使用@SqlResultSetMaps定义本机查询结果到DTO类的映射。有关更多详细信息,请查看博客文章。