问题描述
我使用 Spring Boot 和 QueryDSL 来组合 sql 查询和谓词。问题是我必须创建一个谓词来根据电子邮件从表中获取数据但是:
- 电子邮件可以在 Freight.sender.email 中
- 或在 Freight.message.senderAddress 中
其中 Freight、Message、Sender 当然是表。
在 Freight 表中,我们可以有空的 sender_id 或 message_id,因此我必须通过电子邮件从 Freight.sender.email
或 Freight.message.senderAddress
(如果 Freight.sender
为空)
是否可以创建这样一个谓词,将来自请求查询参数的电子邮件与 Freight.sender.email 进行比较,并且仅当 Freight.sender.email 不存在时,我的谓词才会在 Freight.message.senderAddress 中搜索电子邮件
public Predicate build(Map<String,String> filters) {
return new OptionalBooleanBuilder(Expressions.asBoolean(true).isTrue())
.notNullAnd(qFreight.loadingAddress::containsIgnoreCase,filters.get(LOADING_ADDRESS))
.notNullAnd(qFreight.unloadingAddress::containsIgnoreCase,filters.get(UNLOADING_ADDRESS))
.notNullAnd(qFreight.loadingDate.eq(filters.get(LOADING_DATE) != null ? LocalDate.parse(filters.get(LOADING_DATE)) : Now()),filters.get(LOADING_DATE))
.notNullAnd(qFreight.unloadingDate.eq(filters.get(UNLOADING_DATE) != null ? LocalDate.parse(filters.get(UNLOADING_DATE)) : Now()),filters.get(UNLOADING_DATE))
//MY ATTEMPT - NOT WORKING:
.notNullAnd(qFreight.sender.email.eq(filters.get(SENDER_EMAIL)).or(qFreight.emailMessage.senderAddress.eq(SENDER_EMAIL)),filters.get(SENDER_EMAIL))
.build();
}
public class OptionalBooleanBuilder {
private BooleanExpression predicate;
public OptionalBooleanBuilder(BooleanExpression predicate) {
this.predicate = predicate;
}
public <T> OptionalBooleanBuilder notNullAnd(Function<T,BooleanExpression> expressionFunction,T value) {
if (nonNull(value)) {
return new OptionalBooleanBuilder(predicate.and(expressionFunction.apply(value)));
}
return this;
}
public BooleanExpression build() {
return predicate;
}
public <T>OptionalBooleanBuilder notNullAnd(BooleanExpression expression,T value) {
if(nonNull(value)){
return new OptionalBooleanBuilder(predicate.and(expression));
}
return this;
}
}
更新
来自以下建议:
private Predicate addPredicate(OptionalBooleanBuilder builder,String email) {
if (nonNull(email)) {
return builder.notNullAnd(qFreight.sender.email.coalesce(qFreight.emailMessage.senderAddress.eq(email)).asBoolean(),email).build();
return builder.build();
}
出现错误:
antlr.NoViableAltException: unexpected AST node: (
at org.hibernate.hql.internal.antlr.HqlsqlbaseWalker.logicalExpr(HqlsqlbaseWalker.java:2169) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.antlr.HqlsqlbaseWalker.logicalExpr(HqlsqlbaseWalker.java:2089) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.antlr.HqlsqlbaseWalker.whereClause(HqlsqlbaseWalker.java:827) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.antlr.HqlsqlbaseWalker.query(HqlsqlbaseWalker.java:621) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.antlr.HqlsqlbaseWalker.selectStatement(HqlsqlbaseWalker.java:325) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.antlr.HqlsqlbaseWalker.statement(HqlsqlbaseWalker.java:273) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
2020-12-24 00:45:35.535 ERROR 16068 --- [nio-9090-exec-8] p.a.m.s.filter.JwtAuthorizationFilter : Request processing Failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: ( near line 3,column 52 [select freight
from pl.appwise.mtf.freight.domain.model.Freight freight
where ?1 = ?1 and freight.user.id = ?2 and coalesce(freight.sender.email,freight.emailMessage.senderAddress = ?3)
order by freight.loadingDate desc]; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: ( near line 3,freight.emailMessage.senderAddress = ?3)
order by freight.loadingDate desc]
2020-12-24 00:45:37.906 INFO 16068 --- [ scheduling-1] ilAccoun
解决方法
使用Freight.sender.email.coalesce(Freight.message.senderAddress)
。如果 Freight.message.senderAddress
是 NULL
,Freight.message
将是 NULL
。对于可选关联,默认情况下使用左外连接,因此这不会导致问题。否则,请自己明确使用左连接。