JPA双向实体:在查询父实体时仅选择子实体的子集

Posted

技术标签:

【中文标题】JPA双向实体:在查询父实体时仅选择子实体的子集【英文标题】:JPA bidirectional entities: Select only a sub-set of child entities while query for Parent entities 【发布时间】:2021-05-01 09:34:45 【问题描述】:

假设我有一个Parent,它有一个SetChild 实体。

@Entity
public class Parent 
    //...
    @OneToMany(mappedBy = "parent")
    Set<Child> children = new HashSet<>();
    //...


@Entity
public class Child 
    //...
    @ManyToOne
    @JoinColumn(name = "parent_id", nullable = false)
    private Parent parent;
    //...
   
    private Integer someProperty;

我想选择Parent 实体列表,其中Child 有一些规范。为此,我使用这样的查询:

@Query(value = "select distinct p from Parent p left join p.children c where c.someProperty > ?1")

通过这个查询,我拥有他们的孩子拥有的所有Parent 实体someProperty &gt; someValue

问题在于,在service 类中,当我获取Parent 实例的子代时,Hibernate 会从数据库中加载所有子代,而我只希望子集查询中满足该规范的子代父母的孩子。

【问题讨论】:

【参考方案1】:

你可以使用filters:

@FilterDef(
    name="childrenFilter",
    parameters=@ParamDef(name="parameter", type="int" ))
@Entity
public class Parent 
    //...
    @FilterJoinTable(
        name="childrenFilter",
        condition="childProperty > :parameter")
    @OneToMany(mappedBy = "parent")
    Set<Child> children = new HashSet<>();
    //...

如果你想使用过滤器,你需要启用它们:

String jpql = "select distinct p from Parent p left join p.children c where c.someProperty > ?1";
entityManager
    .unwrap( Session.class )
    .enableFilter( "childrenFilter" )
    .setParameter( "parameter", 11)
    .createQuery(jpql, Parent.class)
    .setParameter(1, 11)
    .getResultList();

您可以在查询后禁用过滤器:

entityManager
    .unwrap( Session.class ) 
    .disableFilter( "childrenFilter" );

【讨论】:

谢谢!两个问题: 1- 如何在 Spring Boot 中使用过滤器实现查询?如何启用/禁用过滤器?例如在后台服务中我们不需要过滤器。 我不知道 Spring Boot 开箱即用地处理它们。但是它们只有在您使用实体管理器启用它们时才有效,因此您只能在运行查询之前启用它们并在之后禁用它们

以上是关于JPA双向实体:在查询父实体时仅选择子实体的子集的主要内容,如果未能解决你的问题,请参考以下文章

使用 JPA 连接从父实体返回子实体

如何通过 JPA 查询按子类实体值获取父实体?

是否有 JPA / JPQL 查询来搜索春季作为 JSON 传递的实体子集?

仅选择实体集合的子集

JPA+Hibernate - 实体关系中的循环 - 级联策略

实体框架:查询子实体 [重复]