【发布时间】:2021-12-06 01:14:19
【问题描述】:
我正在尝试创建一个Specification 来过滤表格。该表有 2 个@ManyToOne 关系(可以为空),我想在其中应用过滤器。类似于搜索功能。
假设这个结构
public class X {
@ManyToOne(targetEntity = A.class, fetch = FetchType.EAGER)
@JoinColumn(nullable = true, name = "aID")
private A a;
@ManyToOne(targetEntity = B.class, fetch = FetchType.EAGER)
@JoinColumn(nullable = true, name = "bID")
private B b;
}
还假设A 和B 有一个名为name 的String 属性。
所以,我想为X 创建一个Specification,我可以在A 或B 的名称 中匹配String 值。
这是我的方法:
public static Specification<X> filterName(String value) {
return new Specification<X>() {
public Predicate toPredicate(Root<X> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Expression<String> aName = root.get("a").get("name").as(String.class);
Expression<String> bName = root.get("b").get("name").as(String.class);
List<Predicate> predicates = new ArrayList<>();
if (!value.isEmpty()) {
predicates.add(builder.like(aName, "%" + value + "%"));
predicates.add(builder.like(bName, "%" + value + "%"));
}else{
return null;
}
Predicate predicate = builder.or(predicates.toArray(new Predicate[0]));
return predicate;
}
};
}
我真的希望它会起作用,但它没有。
我想要显示 A OR 的 name 和 B 的 name 是 like 输入值的那些行。
如果我启用日志以显示 SQL 查询,这就是我得到的:
select xentity0_.aId, xentity0_.bId from table_x xtab cross join table_a atab cross join table_b btab where xtab.aId=atab.id and xtab.bId=btab.id and (atab.name like ?) and (btab.名字之类的?)
我认为问题出在where xtab.aId=atab.id and xtab.bId=btab.id 部分。因为A 或B 可以为null,所以并不总是满足该条件。
假设此表为X:
| ID | aId | bId |
|---|---|---|
| 1 | null | 1 |
| 2 | 1 | null |
| 3 | 2 | 2 |
此表为A:
| ID | name |
|---|---|
| 1 | John |
| 2 | Lucy |
此表为B:
| ID | name |
|---|---|
| 1 | Luke |
| 2 | Mike |
当使用 Specification 查找 %Lu% 时,我希望看到的是 X
| ID | aId | bId |
|---|---|---|
| 1 | null | 1 |
| 3 | 2 | 2 |
因为A 中的Lucy 和B 中的Luke。相反,我看到的是最后一行(A 和 B 都不为空)
【问题讨论】:
标签: spring-boot jpa criteria-api many-to-one