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) 只会带来父类型的初始化对象,但是如果执行提取,它将带来初始化的父对象和子对象。
我要做的另一个修改是将标识符的类型更改为非原始类型,以便它接受空值,这是使用序列插入所必需的
我有一个 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) 只会带来父类型的初始化对象,但是如果执行提取,它将带来初始化的父对象和子对象。
我要做的另一个修改是将标识符的类型更改为非原始类型,以便它接受空值,这是使用序列插入所必需的