带有 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 仍在为 SELECT
、INSERT
、UPDATE
、DELETE
语句提供一些新的子句支持,但有一些语句在模型 API 形式中不可用。其中包括 MERGE
、TRUNCATE
、全部 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
表示,并从那里继续工作。
我们有一个在不同情况下使用的具有共同结构的查询(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 仍在为 SELECT
、INSERT
、UPDATE
、DELETE
语句提供一些新的子句支持,但有一些语句在模型 API 形式中不可用。其中包括 MERGE
、TRUNCATE
、全部 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
表示,并从那里继续工作。