带有 SelectQuery 的 jOOQ CommonTableExpression

jOOQ CommonTableExpression with SelectQuery

我们有一个在不同情况下使用的具有共同结构的查询(where 子句不同)

所以我们有这样的东西

val baseQuery: SelectQuery<Record> = dsl
  .select(someFields)
  .from(someTable)
  .join(otherTable).on(joinClause)
  .query

在其他地方,我们会根据需要扩展此查询。

baseQuery.apply {
  addConditions(conditionsA)
}.fetch()

baseQuery.apply {
  addConditions(conditionsB)
}.fetch()

到目前为止一切顺利。但是现在,如果我们能以某种方式将此基础与 CTE 结合使用,那就太棒了。不过不知道该怎么做。

val someCTE: CommonTableExpression<*> = DSL.....

// dsl
//   .with(someCTE)
//   .selectQuery(baseQuery.apply {}) ¯\_(ツ)_/¯

baseQuery.apply {
  // addWith(someCTE) ¯\_(ツ)_/¯
  addSelect(someCTE.field(cteField))
  addJoin(someCTE, joinClause)
  addConditions(conditionsC)
} 

有办法吗?也许其他建议如何在使用 CTE 时重用基本查询?

编辑:解决方案

在 Lukas 的回答的帮助下,我决定采用这种方法

fun dynamicQuery(
  context: SelectSelectStep<*> = dsl.select(),
  selects: List<Field<*>> = listOf(),
  joins: List<Pair<Table<*>, Condition>> = listOf(),
  conditions: List<Condition> = listOf()
): SelectQuery<Record>

所以在正常的定制中我可以

dynamicQuery(
  conditions = conditionsA
).fetch()

dynamicQuery(
  conditions = conditionsB
).fetch()

它可以与 CTE 结合使用

val someCTE: CommonTableExpression<*> = DSL.....
dynamicQuery(
  context = dsl.with(someCTE).select(),
  selects = listOf(someCTE.field(cteField)),
  joins = listOf(someCTE to joinClause),
  conditions = conditionsC
).fetch()

TL;DR:您不能将 CTE 与 jOOQ 3.15 的模型一起使用 API

关于 jOOQ 模型的一些背景知识 API 与 DSL API 的区别

非常古老的 jOOQ 1.0 只有现在所谓的“模型 API”,一个可变的、程序的 API,带有 setter(没有 getter),您可以在其中操纵动态 SQL.

jOOQ 2.0 引入了 DSL API,这是当今大多数人使用的。 DSL API 模仿 SQL 语言这一事实​​帮助用户更容易地发现 jOOQ API。一切都完全按照预期命名。除了 CTE 和派生表领域的一些怪癖外,您可以编写 jOOQ-SQL 几乎就像实际的 SQL.

模型 API 未被弃用,但被 DSL API 包装并保留在:

  • 出于向后兼容的原因
  • 因为有些人似乎喜欢程序方法

你不能用模型 API 做任何你不能用 DSL API 做的事情,尽管在用DSL API。参见:https://blog.jooq.org/2017/01/16/a-functional-programming-approach-to-dynamic-sql-with-jooq

jOOQ 的未来

虽然模型 API 仍在为 SELECTINSERTUPDATEDELETE 语句提供一些新的子句支持,但有一些语句在模型 API 形式中不可用。其中包括 MERGETRUNCATE、全部 DDL statements, all procedural statements。并且,WITH 子句。

策略是最终弃用该模型 API,因为冗余会产生大量额外工作,最好将这些工作投入到其他地方。当人们以意想不到的顺序调用模型 API 方法时,也存在细微的错误,即通过 DSL API.

无法实现的顺序
  • 第一步,很快,jOOQ 将反转 API 之间的关系:https://github.com/jOOQ/jOOQ/issues/11241。模型 API 将成为 DSL API 的辅助包装器,供那些依赖它实现向后兼容的人使用。模型 API 甚至会被提取到一个单独的兼容性模块中,以阻止它在新代码中的使用,这并非不可能
  • 下一步,通过反转依赖关系,DSL API 最终可以变得始终不可变,这是许多用户所期望的,但令他们惊讶的是,他们发现缺少:https://github.com/jOOQ/jOOQ/issues/9047
  • 最终,模型 API 将被弃用,然后被删除

你今天仍然可以使用它,弃用和删除将在很长一段时间内完成,所以不用急着离开这个 API(jOOQ 总是如此)。但是在你的问题的上下文中,很高兴看到 jOOQ 不会再投资添加太多的功能了。 CTE 支持不会添加到模型 API。

解决方法

当然,您可以解决此限制,因为在内部,模型 API 支持 CTE:

  • 您可以使用反射将新的 CTE 添加到 SelectQuery 内部表示。我不会在这里记录它是如何工作的,因为记录这些东西从来都不是一个好主意:)
  • 您可以开始使用 DSL API 创建查询,然后使用 SelectFinalStep.getQuery() 提取内部 SelectQuery 表示,并从那里继续工作。