如何在不使用Q-Class的情况下在QueryDsl中创建动态子查询?

时间:2017-04-21 12:35:56

标签: java querydsl hibernate-onetomany

我对querydsl有点新,目前正致力于我们的任务 想要在不使用生成的Q-class的情况下访问OneToMany相关表,并在其上执行子查询。我们正在使用 QueryDsl 3.7.4 。在此示例中,我们在 date 列上获得了一个简单的 max -Statement。

我试图实现的陈述应该是这样的:

select person
from person p
left join p.instructions as i
where i.validUntil = (
  select max(i.validUntil) from instruction i2 where i2.person = p
)

人员实体:

@OneToMany(cascade = {..},mappedBy = "person")
private Set<Instruction> instructions = new HashSet<>();

指令实体:

@Entity(name = "instruction")
public class Instruction {
  ...
  @Column(name = "validuntil", nullable = true)
  @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
  private LocalDate validUntil;
  ...
}

变量:

query: select baseEntity from person baseEntity [..]
pathBuilder: baseEntity
entityPath: baseEntity.instructions
entityClazz: java.util.Set
propName: validUntil

到目前为止,我尝试了不同的解决方案:

if (entityClazz.isAssignableFrom(Set.class)) {

  CollectionPath<Object, PathBuilder<Object>> collection =
      pathBuilder.getCollection(entityName, entityClazz);

  query.leftJoin(collection.any());

  if ("date".equals(columnModel.getType())) {

    DateSubQuery<LocalDate> sub = new JPASubQuery().from(entityPath).where(collection.any().eq(pathBuilder))
        .unique(collection.any().getDate(propName, LocalDate.class).max());

    query.where(collection.any().getDate(propName, LocalDate.class).eq(sub));

  }
}

导致 IllegalArgumentException:Undeclared path&quot; baseEntity_instructions_64058&#39;。将此路径添加为查询的源,以便能够引用它。
我有点理解,因为我并没有真正宣布&#39; baseEntity_instructions_64058&#39;任何地方。但是我该怎么做呢?

然后我尝试用entityPath替换collection.any()语句:

DateSubQuery<LocalDate> sub =
        new JPASubQuery().from(entityPath).where(entityPath.eq(pathBuilder))
            .unique(entityPath.getDate(propName, LocalDate.class).max());
query.where(entityPath.getDate(propName, LocalDate.class).eq(sub));

生成的查询对我来说不错:

select baseEntity
from Person baseEntity
  ...
left join baseEntity.instructions
where baseEntity.instructions.validUntil = (select max(baseEntity.instructions.validUntil)
from baseEntity.instructions
where baseEntity.instructions = ?1)

..但使用以下消息抛出 org.hibernate.QueryException

使用元素属性引用[validUntil]非法尝试取消引用集合[person0_.auto_id.instructions]

另一种尝试,别名如下:

PathBuilder<IFlattenable> alias = new PathBuilder<IFlattenable>(entityClazz,entityPath.as("subEntity").toString());

query.leftJoin(alias);

DateSubQuery<LocalDate> sub = new JPASubQuery().from(entityPath).where(alias.eq(entityPath))
    .unique(alias.getDate(propName, LocalDate.class).max());
query.where(alias.getDate(propName, LocalDate.class).eq(sub));

生成以下查询:

select baseEntity
from person baseEntity
  ...
  left join Set baseEntity.instructions as subEntity
where baseEntity.instructions as subEntity.validUntil = (select max(baseEntity.instructions as subEntity.validUntil)
from baseEntity.instructions
where baseEntity.instructions as subEntity = baseEntity.instructions)

最终以 antlr.NoViableAltException:意外令牌:设置。我不明白为什么它会增加&#34; Set&#34;到查询。我也希望&#34; baseEntity.instructions为subEntity&#34;只使用一次(在实际连接时),之后只使用别名&#34; subEntity&#34;供参考。

我已经坚持了一段时间了,阅读了很多stackoverflow和github发布的帖子,尝试了很多各种&#34;解决方案&#34;的组合。有人能帮我解决这个问题吗?

先谢谢,我会给你买一杯饮料:)

0 个答案:

没有答案