Querydsl忽略JPA实体的公用表表达式别名

时间:2018-02-01 10:42:02

标签: java sql querydsl

我需要使用QueryDSL使用公用表表达式构建SQL查询:

WITH cte AS (
  SELECT DISTINCT BUSINESS_ID FROM BUSINESS WHERE MERCHANT_CODE like ?
)
SELECT t0.*
FROM PAYMENT t0
  LEFT JOIN cte t1 ON t0.PAYER = t1.BUSINESS_ID
  LEFT JOIN cte t2 ON t0.PAYEE = t2.BUSINESS_ID
WHERE (t1.BUSINESS_ID IS NOT NULL OR t2.BUSINESS_ID IS NOT NULL)

我有两个JPA实体(付款,业务)。

这是我实施的方式:

String merchantCode = "abcd%";
QPayment payment = QPayment.payment;
QBusiness business = QBusiness.business;
QBusiness cte = new QBusiness("cte");
QBusiness merchant1 = new QBusiness("t1");
QBusiness merchant2 = new QBusiness("t2");
Configuration configuration = new Configuration(new OracleTemplates());

new JPASQLQuery<>(entityManager, configuration)
  .with(cte,
      JPAExpressions.selectDistinct(business.businessId).from(business)
      .where(business.merchantCode.like(merchantCode)))
  .select(payment)
  .from(payment)
    .leftJoin(cte, merchant1).on(payment.payer.eq(merchant1.businessId))
    .leftJoin(cte, merchant2).on(payment.payee.eq(merchant2.businessId))
  .where(merchant1.businessId.isNotNull()
      .or(merchant2.businessId.isNotNull()));

问题是在leftJoin期间它并不将cte视为链接,而是插入表名和两个别名:LEFT JOIN BUSINESS cte t1 ON ...。我尝试了不同的模板 - 没有帮助。

我做错了什么或者是QueryDSL错误?

2 个答案:

答案 0 :(得分:1)

JPQL不支持CTE,我们可以在grammar中看到。并且querydsl适用于JPQL。 CTE非常适合特定于供应商,因此您必须执行以下操作之一:

  1. 重写查询以兼容JPA
  2. 使用JPA原生查询
  3. 使用querydsl查询sql(实际上我不记得它是否支持CTE)
  4. 从以上所述我会选择第二个选项。进行本机查询不会损害您的代码。它使您的代码更高效。

答案 1 :(得分:0)

好好看看the tutorial

QCat cat = QCat.cat;
QCat mate = new QCat("mate");
QCat kitten = new QCat("kitten");
query.from(cat)
    .innerJoin(cat.mate, mate)
    .leftJoin(cat.kittens, kitten)
    .list(cat);

您需要.leftjoin(cte.merchant1, merchant1).on(...)或在父“cte”中调用相应字段的任何内容。 基本上,您需要命名要加入的字段。仅仅陈述元模型是不够的,因为没有办法告诉你实际想要什么。您可以在代码中看到它(以及教程的小猫示例中):您有两个商家想要加入 cte ,那么哪一个是哪个。

.on() - 子句只是说明了连接有效的条件,就像你可以在那里放置过滤器一样。