【问题标题】:antlr.NoViableAltException for subquery in then-clause with Querydsl / JPQL / Hibernateantlr.NoViableAltException 用于带有 Querydsl / JPQL / Hibernate 的 then 子句中的子查询
【发布时间】:2016-09-24 17:25:12
【问题描述】:

我的应用程序中有三个实体:Customer、PriceLevel 和 TemporalCustomerPriceLevel。每个客户都有一个名为 defaultPriceLevel 的字段,它直接引用 PriceLevel。可以暂时将客户切换到替代的 PriceLevel。为此,向 TemporalCustomerPriceLevel 添加了一个引用 PriceLevel 和客户的条目。

实体类有:

@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;
  ...
}

我现在想查询活跃价格水平,即。 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

这似乎是有道理的。此外,如果我将两个 JPAExpressions 行替换为固定的 PriceLevel 对象,查询将按预期运行。

所以主要问题是:在case 块的then 子句中使用子查询是否有任何限制?我的 Querydsl 有什么问题吗?非常感谢任何帮助。

【问题讨论】:

    标签: hibernate subquery jpql querydsl case-when


    【解决方案1】:

    我发现以下替代查询可以解决我的问题。不过,如果有人知道 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()
              )
          )
        );
    

    【讨论】:

      猜你喜欢
      • 2014-08-01
      • 2021-05-15
      • 1970-01-01
      • 1970-01-01
      • 2015-10-23
      • 2020-06-05
      • 2019-08-23
      • 2021-01-11
      相关资源
      最近更新 更多