微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JPQL渴望获取元素

如何解决JPQL渴望获取元素

假设以下内容

   @Query("SELECT new so.dto.CustomerWithTotal(s,sum(sb.amount)) from Customer s LEFT join fetch Bills sb ON sb.customer.sq=s.sq and sb.periodFrom <= ?3 and sb.periodTo >= ?2 WHERE s.department.sq=?1 group by s")
   List<CustomerWithTotal> findCustWithOrderTotal(Long departmentId,LocalDate from,LocalDate to);

   public CustomerWithBillTotal(CustomerEo customer,BigDecimal amount) {
      this.customer= customer;
      this.amount = (amount != null) ? amount : BigDecimal.ZERO;
   }

我正在尝试获取特定时期内的客户及其订单总额。但是,当我检查实际执行的查询时,会看到类似以下的内容

Hibernate: select customer.id as col_0_0_,sum(bill.amount) as col_1_0_ from customers...
Hibernate: select customer.id as cpx1_19_0_,customer.jpa_version as jpa_vers2_19_0_,...
Hibernate: select customer.id as cpx1_19_0_,...

Hibernate仅在第一个查询获取id,然后分别请求每个客户,从而导致N + 1个查询。如何使Hibernate在第一个查询中急切地获取customer?最好不列出customer中的所有CustomerWithBillTotal字段?

解决方法

如果您将实体别名传递给JPQL中的构造函数,则Hibernate必须实现完整对象,因此它将以某种方式获取所有字段。据我所知,Hibernate中构造函数表达式的当前实现将始终传递代理(如果您传递实体别名),因此您看到的次要加载是由于Hibernate加载了状态。如果您只想获取实际需要的字段,则需要明确列出它们。

您可能还喜欢Blaze-Persistence Entity Views所提供的服务。

我创建了该库,以允许在JPA模型与自定义接口或抽象类定义的模型之间轻松进行映射,例如类固醇上的Spring Data Projections。这个想法是,您可以按自己喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(获取器)映射到实体模型。

针对您的用例的DTO模型可能与Blaze-Persistence Entity-Views相似,如下所示:

@EntityView(Customer.class)
public interface CustomerWithBillTotal {
    @IdMapping("sq")
    Integer getId();
    String getCustomerName();
    // Other customer mappings you need...

    // Assuming you have a one-to-many association named "bills" in Customer
    @Mapping("COALESCE(SUM(bills.amount),0)")
    // You can also use this if you don't have that association
    // @Mapping("COALESCE(SUM(Bills[customer.sq = VIEW(sq) AND periodFrom <= :periodFrom and periodTo >= :periodTo].amount),0)")
    BigDecimal getAmount();
}

查询是将实体视图应用于查询的问题,最简单的方法就是按ID查询。

CustomerWithBillTotal a = entityViewManager.find(entityManager,CustomerWithBillTotal.class,id);

Spring Data集成使您可以像使用Spring Data Projections一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

   List<CustomerWithTotal> findByDepartmentId(Long departmentId,@OptionalParam("periodFrom") LocalDate from,@OptionalParam("periodTo") LocalDate to);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。