antlr.NoViableAltException 在 then 子句中使用 Querydsl / JPQL / Hibernate 的子查询
antlr.NoViableAltException for subquery in then-clause with Querydsl / JPQL / Hibernate
我的应用程序中有三个实体,Customer、PriceLevel 和 TemporalCustomerPriceLevel。每个客户都有一个名为 defaultPriceLevel 的字段,它直接引用 PriceLevel。 Customers 可以暂时切换到替代 PriceLevel。为此,添加了一个 TemporalCustomerPriceLevel 条目,它引用了 PriceLevel 和 Customer。
实体类是:
@Entity
public class Customer implements Serializable {
...
@ManyToOne
@JoinColumn(name = "default_price_level_id")
private PriceLevel defaultPriceLevel;
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<TemporalCustomerPriceLevel> temporalCustomerPriceLevels
= new ArrayList<TemporalCustomerPriceLevel>();
...
}
@Entity
public class PriceLevel implements Serializable {
...
@OneToMany(mappedBy = "priceLevel", cascade = CascadeType.ALL, orphanRemoval = true)
private List<TemporalCustomerPriceLevel> temporalCustomerPriceLevels;
@OneToMany(mappedBy = "defaultPriceLevel", cascade = CascadeType.PERSIST)
private List<Customer> customers;
...
}
@Entity
public class TemporalCustomerPriceLevel implements Serializable {
...
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "price_level_id")
private PriceLevel priceLevel;
...
}
我现在想查询活跃价格水平,i。 e. defaultPriceLevel 如果没有(活动,为简单起见省略)TemporalCustomerPriceLevel 存在,否则 TemporalCustomerPriceLevel 引用的 PriceLevel。
我使用 Spring、JPA (Hibernate)、MySql 和 Querydsl。在Querydsl中,我写了以下内容:
QCustomer customer = QCustomer.customer;
QTemporalCustomerPriceLevel qt = QTemporalCustomerPriceLevel.temporalCustomerPriceLevel;
SimpleExpression<PriceLevel> cases = new CaseBuilder()
.when(JPAExpressions.select(qt.count()).from(qt).where(qt.customer.eq(customer)).eq(1L))
.then(
JPAExpressions.select(qt.priceLevel).from(qt).where(qt.customer.eq(customer))
)
.otherwise(
JPAExpressions.select(customer.defaultPriceLevel).from(customer)
).as("activePriceLevel");
JPAQuery<Tuple> query = factory.select(customer, cases).from(customer);
这会导致错误:
antlr.NoViableAltException: unexpected AST node: query
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1367) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
...
Querydsl 生成的查询如下所示:
select customer,
(case when ((select count(temporalCustomerPriceLevel)
from TemporalCustomerPriceLevel temporalCustomerPriceLevel
where temporalCustomerPriceLevel.customer = customer) = ?1)
then (select temporalCustomerPriceLevel.priceLevel
from TemporalCustomerPriceLevel temporalCustomerPriceLevel
where temporalCustomerPriceLevel.customer = customer)
else (select customer.defaultPriceLevel
from Customer customer)
end) as activePriceLevel
from Customer customer
这似乎有道理。此外,如果我用固定的 PriceLevel 对象替换两个 JPAExpressions
行,查询将按预期运行。
所以主要问题是:在 case
块的 then
子句中使用子查询是否有任何限制?我的 Querydsl 有什么问题吗?非常感谢任何帮助。
我发现以下备选查询可以解决我的问题。不过,如果有人知道 then 子句中的 hibernate 和 JPQL 子查询,我仍然会感兴趣。
JPAQueryFactory factory = new JPAQueryFactory(em);
QCustomer customer = QCustomer.customer;
QPriceLevel priceLevel = QPriceLevel.priceLevel;
QTemporalCustomerPriceLevel tmp = new QTemporalCustomerPriceLevel("tmp_qtcpl");
Date now = new Date();
JPAQuery<Tuple> query = factory.select(customer, priceLevel).from(customer, priceLevel).where(
JPAExpressions.select(tmp).from(tmp)
.where(tmp.validAfter.loe(now)
.and(tmp.validUntil.after(now)
.and(tmp.priceLevel.eq(priceLevel)
.and(tmp.customer.eq(customer))))).exists()
.or(
customer.defaultPriceLevel.eq(priceLevel)
.and(
JPAExpressions.select(tmp).from(tmp)
.where(tmp.validAfter.loe(now)
.and(tmp.validUntil.after(now)
.and(tmp.customer.eq(customer)))).notExists()
)
)
);
我的应用程序中有三个实体,Customer、PriceLevel 和 TemporalCustomerPriceLevel。每个客户都有一个名为 defaultPriceLevel 的字段,它直接引用 PriceLevel。 Customers 可以暂时切换到替代 PriceLevel。为此,添加了一个 TemporalCustomerPriceLevel 条目,它引用了 PriceLevel 和 Customer。
实体类是:
@Entity
public class Customer implements Serializable {
...
@ManyToOne
@JoinColumn(name = "default_price_level_id")
private PriceLevel defaultPriceLevel;
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<TemporalCustomerPriceLevel> temporalCustomerPriceLevels
= new ArrayList<TemporalCustomerPriceLevel>();
...
}
@Entity
public class PriceLevel implements Serializable {
...
@OneToMany(mappedBy = "priceLevel", cascade = CascadeType.ALL, orphanRemoval = true)
private List<TemporalCustomerPriceLevel> temporalCustomerPriceLevels;
@OneToMany(mappedBy = "defaultPriceLevel", cascade = CascadeType.PERSIST)
private List<Customer> customers;
...
}
@Entity
public class TemporalCustomerPriceLevel implements Serializable {
...
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "price_level_id")
private PriceLevel priceLevel;
...
}
我现在想查询活跃价格水平,i。 e. defaultPriceLevel 如果没有(活动,为简单起见省略)TemporalCustomerPriceLevel 存在,否则 TemporalCustomerPriceLevel 引用的 PriceLevel。
我使用 Spring、JPA (Hibernate)、MySql 和 Querydsl。在Querydsl中,我写了以下内容:
QCustomer customer = QCustomer.customer;
QTemporalCustomerPriceLevel qt = QTemporalCustomerPriceLevel.temporalCustomerPriceLevel;
SimpleExpression<PriceLevel> cases = new CaseBuilder()
.when(JPAExpressions.select(qt.count()).from(qt).where(qt.customer.eq(customer)).eq(1L))
.then(
JPAExpressions.select(qt.priceLevel).from(qt).where(qt.customer.eq(customer))
)
.otherwise(
JPAExpressions.select(customer.defaultPriceLevel).from(customer)
).as("activePriceLevel");
JPAQuery<Tuple> query = factory.select(customer, cases).from(customer);
这会导致错误:
antlr.NoViableAltException: unexpected AST node: query
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1367) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
...
Querydsl 生成的查询如下所示:
select customer,
(case when ((select count(temporalCustomerPriceLevel)
from TemporalCustomerPriceLevel temporalCustomerPriceLevel
where temporalCustomerPriceLevel.customer = customer) = ?1)
then (select temporalCustomerPriceLevel.priceLevel
from TemporalCustomerPriceLevel temporalCustomerPriceLevel
where temporalCustomerPriceLevel.customer = customer)
else (select customer.defaultPriceLevel
from Customer customer)
end) as activePriceLevel
from Customer customer
这似乎有道理。此外,如果我用固定的 PriceLevel 对象替换两个 JPAExpressions
行,查询将按预期运行。
所以主要问题是:在 case
块的 then
子句中使用子查询是否有任何限制?我的 Querydsl 有什么问题吗?非常感谢任何帮助。
我发现以下备选查询可以解决我的问题。不过,如果有人知道 then 子句中的 hibernate 和 JPQL 子查询,我仍然会感兴趣。
JPAQueryFactory factory = new JPAQueryFactory(em);
QCustomer customer = QCustomer.customer;
QPriceLevel priceLevel = QPriceLevel.priceLevel;
QTemporalCustomerPriceLevel tmp = new QTemporalCustomerPriceLevel("tmp_qtcpl");
Date now = new Date();
JPAQuery<Tuple> query = factory.select(customer, priceLevel).from(customer, priceLevel).where(
JPAExpressions.select(tmp).from(tmp)
.where(tmp.validAfter.loe(now)
.and(tmp.validUntil.after(now)
.and(tmp.priceLevel.eq(priceLevel)
.and(tmp.customer.eq(customer))))).exists()
.or(
customer.defaultPriceLevel.eq(priceLevel)
.and(
JPAExpressions.select(tmp).from(tmp)
.where(tmp.validAfter.loe(now)
.and(tmp.validUntil.after(now)
.and(tmp.customer.eq(customer)))).notExists()
)
)
);