在可为空的引用属性上使用 Spring-Data 和 QueryDSL 进行过滤
Filter with Spring-Data and QueryDSL on nullable reference attribute
我有以下问题。我正在使用 Jquery Datatable 服务器端,我现在正在实现搜索框。但是在特殊情况下我有一个问题,当数据集有一个属性时,"null" 是什么。所以数据集不会被发现,尽管它应该找到因为它在一个属性上匹配。
一开始的情况是这样的。您会看到学徒 Fabio Bartels 有一个数据集,他没有 Fachrichtung。以及 Viktoria 的数据集。
现在当我搜索 Viktoria 时,过滤器按预期工作:
当我搜索 Fabio 时,找不到数据集:
=====
我遇到的问题是,我不知道如何处理过滤器,只有当属性不为空时,才会针对搜索字符串验证属性。
=====
服务器端 Java Class如下所示:
查询Class:
class ContractSearchQuery {
private static QContract contract = QContract.contract;
static BooleanExpression getPredicate(final ContractSearch filter) {
BooleanExpression predicate;
if (filter == null || filter.isEmpty()) {
// SHOW ALL PREDICATE ...
} else {
final String search = filter.getSearch();
final List<BooleanExpression> expressions = new ArrayList<BooleanExpression>();
// EXPRESSIONS CURRENTLY ONLY ON AUSZUBILDENDER AND FACHRICHTUNG
// FOR SHOWCASE
expressions.add(containsApprenticeName(search)); // AUSZUBILDENDER
expressions.add(containsSpecialisation(search)); // FACHRICHTUNG
BooleanExpression expression = expressions.get(INTEGER_ZERO);
for (int i = 1; i < expressions.size(); i++) {
expression = expression.or(expressions.get(i));
}
predicate = expression;
}
return predicate;
}
private static BooleanExpression containsApprenticeName(final String search) {
final BooleanExpression expLastName = contract.apprentice.lastName.containsIgnoreCase(search);
final BooleanExpression expFirstName = contract.apprentice.firstName.containsIgnoreCase(search);
return expLastName.or(expFirstName);
}
private static BooleanExpression containsSpecialisation(final String search) {
return contract.companyOccupationCombination.occupationCombination.specialisation.name.containsIgnoreCase(search);
}
}
Spring-数据存储库调用:
final PageRequest pageRequest = new PageRequest(firstResult / maxResults, maxResults, orderSort);
final Page<Contract> page = contractRepository.findAll(predicate, pageRequest);
return page.getContent();
=======
数据库:
顺便说一句,当我通过加入专业化 Table 对我的数据库进行直接请求时,我认识到,然后我只得到 Fabio 作为记录,当不加入专业化时,我得到了所有三个人。也许与我的问题有关:
select a.first_name, a.last_name from contract c
join company_occupation_combination coc on c.company_occupation_combination = coc.id
join occupation_combination oc on coc.occupation_combination = oc.id
join apprentice a on c.apprentice = a.id
结果:
"Fabio";"Bartels"
"Viktoria";"Kruczek"
"Lina";"Ehleiter"
加入:
select a.first_name, a.last_name from contract c
join company_occupation_combination coc on c.company_occupation_combination = coc.id
join occupation_combination oc on coc.occupation_combination = oc.id
join specialisation s on oc.specialisation = s.id
join apprentice a on c.apprentice = a.id
结果: "Viktoria";"Kruczek"
====
编辑:
好的,在 db 站点上我发现(使用 Hibernate 和 JPA 我开始忘记 SQL-Basices ;-)),我需要一个左连接用于可空关系,所以我的查询应该导致 sql 喜欢:
select a.first_name, a.last_name from contract c
join company_occupation_combination coc on c.company_occupation_combination = coc.id
join occupation_combination oc on coc.occupation_combination = oc.id
left join specialisation s on oc.specialisation = s.id
join apprentice a on c.apprentice = a.id
====
所以我的问题是,当我有一个使用 QueryDSL 和 Spring-Data-Repository 的 Query-Class 时,如何管理左连接?
如果你真的需要左连接,你不能通过谓词实现(相反可以通过子查询)
为了能够进行左连接,您将需要 JPAQuery。
假设您已经配置了存储库,并且能够使用 EntitiManager
,实施 ContractRepositoryCustom
,那么在您的实施中您可以拥有
@PersistenceContext(unitName = "unitname")
protected EntityManager entityManager;
public List<Contract> findAllContracts() {
return new JPAQuery(entityManager, HQLTemplates.DEFAULT)
.from(QContract.contract)
.join(QContract.contract.companyOccupationCombination, QCompanyOccupationCombination.companyOccupationCombination)
.join(QCompanyOccupationCombination.companyOccupationCombination.occupationCombination, QOccupationCombination.occupationCombination)
.leftJoin(QOccupationCombination.occupationCombination.specialization, QSpecialization.specialization)
.join(QSpecialization.specialization.apprentice, QApprentice.apprentice)
.list(QContract.contract);
}
对于分页,您始终应用 limit(maxResults)
和 offset(firstResult)
我真的很喜欢使用 Spring-Data 和 Query-DSL,因为它使我的代码非常整洁。但我真的很惊讶,对于可空引用的情况似乎没有解决方案。当然,您可以使用另一个解决方案,如提到的@vtorosyan,再次感谢您提供该解决方案,但是当您的项目是结合 QueryDSL 和 Spring-Data 构建的时,您真的不想在其中引入第二种样式你的申请。
但是我需要一个解决方案,所以我现在做了以下事情。
问题的关键是,当我使用来自可空实体的数据时,执行了一个连接,它隐藏了数据集,这些数据集上有空引用,请参见上面的示例。我现在所做的,我希望我不会在该项目的后期使用该解决方案遇到另一个问题。我做了 null 对 not null 的引用,并定义了类似 null-record.
的东西
示例我添加了一条专业化记录,例如
ID NAME
0 Keine
我现在使用该记录而不是 null,直到现在具有以下效果:
首先,我的 table 现在显示所有未设置的属性的“Keine”(英文“None”)。使用文本输出然后使用空字符串时看起来更一致。
现在,当我对没有专业化设置的数据记录感兴趣时,我可以明确搜索“Keine”。
而且我的搜索框按预期的方式工作,没有指定的记录。 (这是我从一开始就想解决的问题):
除了该搜索框之外,我还使用模式对话框进行过滤。现在我可以为“可空”记录明确过滤“Keine”:
如果您认为在不使用 Spring-Data 和 QueryDSL 重新构建代码的情况下有另一个解决该问题的好方法,请不要犹豫 post ;-)
我有以下问题。我正在使用 Jquery Datatable 服务器端,我现在正在实现搜索框。但是在特殊情况下我有一个问题,当数据集有一个属性时,"null" 是什么。所以数据集不会被发现,尽管它应该找到因为它在一个属性上匹配。
一开始的情况是这样的。您会看到学徒 Fabio Bartels 有一个数据集,他没有 Fachrichtung。以及 Viktoria 的数据集。
现在当我搜索 Viktoria 时,过滤器按预期工作:
当我搜索 Fabio 时,找不到数据集:
=====
我遇到的问题是,我不知道如何处理过滤器,只有当属性不为空时,才会针对搜索字符串验证属性。
=====
服务器端 Java Class如下所示:
查询Class:
class ContractSearchQuery {
private static QContract contract = QContract.contract;
static BooleanExpression getPredicate(final ContractSearch filter) {
BooleanExpression predicate;
if (filter == null || filter.isEmpty()) {
// SHOW ALL PREDICATE ...
} else {
final String search = filter.getSearch();
final List<BooleanExpression> expressions = new ArrayList<BooleanExpression>();
// EXPRESSIONS CURRENTLY ONLY ON AUSZUBILDENDER AND FACHRICHTUNG
// FOR SHOWCASE
expressions.add(containsApprenticeName(search)); // AUSZUBILDENDER
expressions.add(containsSpecialisation(search)); // FACHRICHTUNG
BooleanExpression expression = expressions.get(INTEGER_ZERO);
for (int i = 1; i < expressions.size(); i++) {
expression = expression.or(expressions.get(i));
}
predicate = expression;
}
return predicate;
}
private static BooleanExpression containsApprenticeName(final String search) {
final BooleanExpression expLastName = contract.apprentice.lastName.containsIgnoreCase(search);
final BooleanExpression expFirstName = contract.apprentice.firstName.containsIgnoreCase(search);
return expLastName.or(expFirstName);
}
private static BooleanExpression containsSpecialisation(final String search) {
return contract.companyOccupationCombination.occupationCombination.specialisation.name.containsIgnoreCase(search);
}
}
Spring-数据存储库调用:
final PageRequest pageRequest = new PageRequest(firstResult / maxResults, maxResults, orderSort);
final Page<Contract> page = contractRepository.findAll(predicate, pageRequest);
return page.getContent();
=======
数据库:
顺便说一句,当我通过加入专业化 Table 对我的数据库进行直接请求时,我认识到,然后我只得到 Fabio 作为记录,当不加入专业化时,我得到了所有三个人。也许与我的问题有关:
select a.first_name, a.last_name from contract c
join company_occupation_combination coc on c.company_occupation_combination = coc.id
join occupation_combination oc on coc.occupation_combination = oc.id
join apprentice a on c.apprentice = a.id
结果: "Fabio";"Bartels" "Viktoria";"Kruczek" "Lina";"Ehleiter"
加入:
select a.first_name, a.last_name from contract c
join company_occupation_combination coc on c.company_occupation_combination = coc.id
join occupation_combination oc on coc.occupation_combination = oc.id
join specialisation s on oc.specialisation = s.id
join apprentice a on c.apprentice = a.id
结果: "Viktoria";"Kruczek"
====
编辑: 好的,在 db 站点上我发现(使用 Hibernate 和 JPA 我开始忘记 SQL-Basices ;-)),我需要一个左连接用于可空关系,所以我的查询应该导致 sql 喜欢:
select a.first_name, a.last_name from contract c
join company_occupation_combination coc on c.company_occupation_combination = coc.id
join occupation_combination oc on coc.occupation_combination = oc.id
left join specialisation s on oc.specialisation = s.id
join apprentice a on c.apprentice = a.id
====
所以我的问题是,当我有一个使用 QueryDSL 和 Spring-Data-Repository 的 Query-Class 时,如何管理左连接?
如果你真的需要左连接,你不能通过谓词实现(相反可以通过子查询)
为了能够进行左连接,您将需要 JPAQuery。
假设您已经配置了存储库,并且能够使用 EntitiManager
,实施 ContractRepositoryCustom
,那么在您的实施中您可以拥有
@PersistenceContext(unitName = "unitname")
protected EntityManager entityManager;
public List<Contract> findAllContracts() {
return new JPAQuery(entityManager, HQLTemplates.DEFAULT)
.from(QContract.contract)
.join(QContract.contract.companyOccupationCombination, QCompanyOccupationCombination.companyOccupationCombination)
.join(QCompanyOccupationCombination.companyOccupationCombination.occupationCombination, QOccupationCombination.occupationCombination)
.leftJoin(QOccupationCombination.occupationCombination.specialization, QSpecialization.specialization)
.join(QSpecialization.specialization.apprentice, QApprentice.apprentice)
.list(QContract.contract);
}
对于分页,您始终应用 limit(maxResults)
和 offset(firstResult)
我真的很喜欢使用 Spring-Data 和 Query-DSL,因为它使我的代码非常整洁。但我真的很惊讶,对于可空引用的情况似乎没有解决方案。当然,您可以使用另一个解决方案,如提到的@vtorosyan,再次感谢您提供该解决方案,但是当您的项目是结合 QueryDSL 和 Spring-Data 构建的时,您真的不想在其中引入第二种样式你的申请。
但是我需要一个解决方案,所以我现在做了以下事情。
问题的关键是,当我使用来自可空实体的数据时,执行了一个连接,它隐藏了数据集,这些数据集上有空引用,请参见上面的示例。我现在所做的,我希望我不会在该项目的后期使用该解决方案遇到另一个问题。我做了 null 对 not null 的引用,并定义了类似 null-record.
的东西示例我添加了一条专业化记录,例如
ID NAME
0 Keine
我现在使用该记录而不是 null,直到现在具有以下效果:
首先,我的 table 现在显示所有未设置的属性的“Keine”(英文“None”)。使用文本输出然后使用空字符串时看起来更一致。
现在,当我对没有专业化设置的数据记录感兴趣时,我可以明确搜索“Keine”。
而且我的搜索框按预期的方式工作,没有指定的记录。 (这是我从一开始就想解决的问题):
除了该搜索框之外,我还使用模式对话框进行过滤。现在我可以为“可空”记录明确过滤“Keine”:
如果您认为在不使用 Spring-Data 和 QueryDSL 重新构建代码的情况下有另一个解决该问题的好方法,请不要犹豫 post ;-)