【问题标题】:Querydsl ignores common table expression alias for JPA EntitiesQuerydsl 忽略 JPA 实体的公用表表达式别名
【发布时间】:2018-02-01 10:42:02
【问题描述】:

我需要使用 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 错误?

【问题讨论】:

    标签: java sql querydsl


    【解决方案1】:

    JPQL 不支持 CTE,正如我们在 grammar 中看到的那样。 querydsl 在 JPQL 上工作。 CTE 非常特定于供应商,因此您必须执行以下操作之一:

    1. 将查询重写为与 JPA 兼容
    2. 使用 JPA 原生查询
    3. 用querydsl查询sql(其实我不记得是否支持CTE)

    从以上所有内容中,我会选择第二个选项。进行本机查询不会损害您的代码。它使您的代码更高效。

    【讨论】:

    • 你确定你没有混淆JPAQueryJPASQLQuery。第一个没有机会创建 CTE,但第二个扩展 AbstractSQLQuery 并且它具有 with() 方法。我希望我可以使用原生,但我还需要添加 0-4 个动态条件。我的一个朋友建议使用 JDBC 模板。到目前为止,我将沿着这条路走。
    • @ShamilAbsalikov 对不起,我真的把他们弄糊涂了
    • @ShamilAbsalikov 但我仍然认为原生会更好。 Jdbc 模板,jooq - 任何东西都可以。我会告诉你更多:没有人可以禁止你用 ifs 构建查询字符串,然后也用这些 ifs 绑定参数
    【解决方案2】:

    好好看看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”中调用的任何相应字段。 基本上,您需要命名要加入的字段。仅仅陈述元模型是不够的,因为没有办法说出你真正想要什么。您可以在您的代码中看到它(以及在教程的小猫示例中):您有两个 Merchant 要加入到 cte,所以哪个是哪个。

    .on()-clause 仅说明联接有效的条件,就像您可以在那里放置过滤器一样。

    .

    【讨论】:

    • 我认为连接限制仅适用于 JPQL,与 SQLQuery 不同,我可以 join(entity, alias).on(join_condition) see "Alternatively the join condition..."。别名用于区分正在连接的一个 CTE 的两个实例。由于JPASQLQuery 是基于AbstractSQLQuery 我相信我可以使用那个join-method。
    • 啊,我明白了。也许该方法取决于“适当的”元模型。我强烈建议自动创建你的元模型(Maven、Gradle),首先你可以跳过new QMyEntity("name") 部分,另外你可以确定模型实际上是正确的。无论如何,Cat-Example 应该可以工作,即使表之间首先没有关系。这样做了很多次
    猜你喜欢
    • 2018-09-28
    • 2014-04-13
    • 2023-01-10
    • 2021-05-24
    • 2018-10-16
    • 2014-08-15
    • 1970-01-01
    • 2016-07-02
    • 2014-08-28
    相关资源
    最近更新 更多