语法错误,QueryDSL"案例何时"在地图上<>字段,汇总

时间:2015-12-22 11:42:26

标签: java hibernate exception syntax querydsl

我有一个event表和一个eventData表,链接为Map<>和Hibernate

事件 - &gt;地图&LT;&GT; eventDatas

@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name = "event_id", referencedColumnName = "event_id")
@MapKey(name = "idk.key")
public Map<DATA_KEY, eventData> getEventDatas() {
    return eventDatas;
}

然后我获得了这个QueryDSL来获取按日期分组的event聚合。

如果Map<>包含DATA_KEY.CODE=202对,则该组为"OK",否则,如果该对缺失或具有不同的值,则该组为"FAIL"。< / p>

final QEvent event = QEvent.event;

Expression<String> groupCase = 
    event.eventDatas.get(DATA_KEY.CODE).valueInt 
    .when(202).then("OK") 
    .otherwise("FAIL");

ConstructorExpression<StatDto> constructor = 
    Projections.constructor(StatDto.class, event.date, event.count(), groupCase);

query.select(constructor) 
    .from(event) 
    .leftJoin(event.eventDatas) 
    .groupBy(event.date, groupCase) 
    .orderBy(event.date.asc());

return query.fetch();

此查询返回错误:

org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: with near line 2, column 73 
[select event.date, count(event), case when event_eventDatas_0.valeurInt = ?1 then 'OK' else 'FAIL' end
from event.eventDatas as event_eventDatas_0 with key(event_eventDatas_0) = ?2, entitystat.event event
  left join event.eventDatas
group by event.date, case when event.eventDatas.get(?2).valeurInt = ?1 then 'OK' else 'FAIL' end
order by event.date]
    at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:91)
    at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:109)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:304)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:203)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:158)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:131)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:93)
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:167)
    at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:301)
    at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1836)
    at com.querydsl.jpa.hibernate.DefaultSessionHolder.createQuery(DefaultSessionHolder.java:36)
    at com.querydsl.jpa.hibernate.AbstractHibernateQuery.createQuery(AbstractHibernateQuery.java:104)
    at com.querydsl.jpa.hibernate.AbstractHibernateQuery.createQuery(AbstractHibernateQuery.java:97)
    at com.querydsl.jpa.hibernate.AbstractHibernateQuery.fetch(AbstractHibernateQuery.java:174)

在查询中没有groupCase,错误消失,证明问题来自案例本身。

Map<>案例与聚合一起使用的正确语法是什么?

附录:

错误指向with行中的from令牌:

from event.eventDatas as event_eventDatas_0 with key(event_eventDatas_0) = ?2

这是没有groupCase的Hibernate生成的SQL:

select event0_.date as col_0_0_, count(event0_.event_id) as col_1_0_ 
from event event0_ 
group by event0_.date
order by event0_.date

2 个答案:

答案 0 :(得分:0)

在异常中它显示了如何执行sql查询。

<强> 选择
event.date,
计数(事件),
event_eventDatas_0.valeurInt =?1的情况然后'OK'否则'FAIL'结束

event.eventDatas as event_eventDatas_0 with key(event_eventDatas_0)=?2,entitystat.event event < em> left join event.eventDatas
group by event.date, case when event.eventDatas.get(?2).valeurInt = ?1 then 'OK' else 'FAIL' end
订购 event.date

选择不应包含与投影refference

相关的任何表达式

上面的group by sql应该是 group by event.date, alisaName

针对您案例的正确sql语句:
选择
event.date,
计数(事件),
event_eventDatas_0.valeurInt =?1然后'OK'否则'FAIL'结束 as aliasName

event.eventDatas as event_eventDatas_0 with key(event_eventDatas_0)=?2,entitystat.event event < em> left join event.eventDatas
group by event.date, aliasName
订购 event.date

我没有测试下面的代码,但假设这应该修复它(添加Alias是正确的方法来解决它)。

final QEvent event = QEvent.event;
final QEventData eventData = QEventData.eventData;

String alias="alias";

Expression<String> groupCase = 
event.eventDatas.get(DATA_KEY.CODE).valueInt 
.when(202).then("OK") 
.otherwise("FAIL").as(alias);

ConstructorExpression<StatDto> constructor = 
Projections.constructor(StatDto.class, event.date, event.count(), groupCase);

query.select(constructor) 
.from(event) 
.leftJoin(event.eventDatas,eventData) 
.groupBy(event.date, alias) 
.orderBy(event.date.asc());

return query.fetch();

答案 1 :(得分:0)

阅读你的问题我得出了与你相同的结论:

  
      
  • 问题显然来自于,我不知道如何删除它
  •   

可能甚至不可能使用Hibernate,我最好的猜测是它无法预测在查询投影中使用CASE WHEN表达式时应该使用什么值来创建新对象。

您可以通过更改查询投影的构造函数来获取EventData键值,然后在StatDto构造函数中应用先前的CASE WHEN逻辑来解决此问题,如下所示:

首先,注释为@QueryProjection的构造函数:

class StatDto {

  private Date eventDate;
  private int eventCount;
  private String eventDataStatus;

  @QueryProjection
  public StatDto(Date eventDate, int eventCount, int eventDataKey){
     this.eventDate = eventDate;
     this.eventCount = eventCount;
     if (eventDataKey == 202) {
        this.eventDataStatus = "OK";
     } else {
        this.eventDataStatus = "FAIL";
     }
  }

}

查询投影构造函数:

query.from(event) 
    .leftJoin(event.eventDatas) 
    .groupBy(event.date, groupCase) 
    .orderBy(event.date.asc())
    .list(ConstructorExpression.create(StatDto.class, event.date, event.count(), event.eventDatas.get(DATA_KEY.CODE).valueInt));

注意:我不知道上述方法是否与此完全相同,如果无论如何它都不能与显示的代码一起使用,请尝试使用给定的想法更改代码。

等待您的反馈,祝您好运!