JPA Criteria API 加入 3 个表和一些空元素

JPA Criteria API join on 3 tables and some null elements

我有一个 parent 实体,它有两个 child 实体作为属性。 我想 select 来自 parent 实体的所有元素,这些元素要么有一个 child一个具有给定参数作为个人属性,要么 child两个具有相同给定参数作为个人属性.

下面是我的三个类简化版:

Parent Object:

@Entity
public class ParentObject {

    @Id
    private int id;

    private int fkChildOne;

    private int fkChildTwo;

    @ManyToOne
    @JoinColumn(name = "fk_child_one_id", referencedColumnName = 
    "child_one_id")
    private ChildOne childOne;

    @ManyToOne
    @JoinColumn(name = "fk_child_one_id", referencedColumnName = 
    "child_one_id")
    private ChildTwo childTwo;

// getters and setters

}

Child一个Object:

@Entity 
public class ChildOne {

    @Id
    private int childOneId;

    private String nameChildOne;

    @OneToMany
    @JoinColumn(name = "fk_child_one_id")
    private List<ParentObject> parents;


// getters and setters

}

Child两个Object:

@Entity
public class ChildTwo {

    @Id
    private int childOneId;

    private String nameChildTwo;

    @OneToMany
    @JoinColumn(name = "fk_child_two_id")
    private List<ParentObject> parents;


// getters and setters

}

规格Class:

   public static Specification<ParentObject> checkName(String name) {

     return Specifications.where(
             (root, query, builder) -> {

                 final Join<ParentObject, ChildOne> joinchildOne = 
                 root.join("childOne");

                 final Join<ParentObject, ChildTwo > joinchildTwo = 
                 root.join("childTwo");

                 return builder.or(
                         builder.equal(joinchildOne .get("nameChildOne"), name),
                         builder.equal(joinchildTwo .get("nameChildTwo"), name)
                         );
             }
     );
    }

在我的服务中调用此规范时,我没有得到任何结果。但是,如果我在我的 builder.or 方法中注释掉两个连接之一和相应的 Predicate,那么我会得到一些结果,但它们显然与我要查找的内容不匹配,即 select 每个 ParentObject 具有 Child一个具有该参数或 Child两个具有该参数。

知道代码有什么问题吗?

终于找到了解决方案:要获取所有相应的结果,我必须添加将成为左连接的连接类型,因为我想获取所有 ParentObjects 而不管拥有 childOne 或 ChildTwo 对象。

final Join<ParentObject, ChildOne> joinchildOne = 
                 root.join("childOne", JoinType.LEFT);

                 final Join<ParentObject, ChildTwo > joinchildTwo = 
                 root.join("childTwo", JoinType.LEFT);

太好了,现在你必须选择是否需要加入或fetch.To优化查询和内存,你应该将关系建立为Lazy (@ManyToMany (fetch = FetchType.LAZY)) , 所以你只会带你需要的东西。

主要区别是Join定义了一个变量中的表的交叉,并允许你使用它,提取select子句中的某些字段,例如,另一方面,fetch使它喂养 属性 的所有对象。在你的例子中, select from parent with join of children (once the relation is set to lazy) 只会带来父类型的初始化对象,但是如果执行提取,它将带来初始化的父对象和子对象。

我要做的另一个修改是将标识符的类型更改为非原始类型,以便它接受空值,这是使用序列插入所必需的