2016-05-26 93 views
1

我的應用程序中有三個實體,Customer,PriceLevel和TemporalCustomerPriceLevel。每個客戶都有一個名爲defaultPriceLevel的字段,它直接引用PriceLevel。暫時,客戶可以切換到替代PriceLevel。爲此,添加了一個TemporalCustomerPriceLevel條目,該條目引用了PriceLevel和Customer。antlr.NoViableAltException子句查詢中的子查詢與Querydsl/JPQL /休眠

的實體類:

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

我現在要查詢活動的價格水平,我。即defaultPriceLevel if否(活躍,爲簡單起見,省略)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行,則查詢按預期運行。

所以主要的問題是:在then塊中使用子查詢有沒有任何限制條款?case塊?我的Querydsl有問題嗎?任何幫助非常感謝。

回答

0

我已經發現以下替代查詢可以解決我的問題。儘管如此,如果有人知道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() 
     ) 
    ) 
    );