JOOQ:在通用界面中对来自不同表的列进行逻辑分组

Posted

技术标签:

【中文标题】JOOQ:在通用界面中对来自不同表的列进行逻辑分组【英文标题】:JOOQ: Logically group columns from different tables in common interface 【发布时间】:2019-03-02 15:25:47 【问题描述】:

我们有一个表格设计,其中很多表格共享一些列,例如在一种情况下,我们的一些表具有markedForDeletion 列。在另一种情况下,我们的多个表都有approvedAtapprovedBy 列。这些表在 JOINED 数据方面不共享任何内容,因此,我不喜欢为这些表引入一个通用的 JOIN 表(由于性能问题,这也不是一个选项)。

但从应用程序的角度来看,我确实有非常相似的任务要执行,在这里。例如,如果我创建一个新行,我在哪个表中插入条目并不重要,我需要从请求中提取批准者和请求时间以将其与另一行一起填充到我的表中稍后在我的代码中的数据。

在 JOOQ 中,我现在可以做类似的事情

private void insertApprovalInformation(Record record, RequestContext ctx) 
   record.set(DSL.field("approver"), ctx.getRequestUser());
   record.set(DSL.field("approvedAt"), ctx.getRequestTime());

但是,我会用这种方法失去所有我心爱的类型安全性。 理想情况下,我想写一些类似的东西

private void insertApprovalInformation(Approvablerecord record, RequestContext ctx) 
   record.set(ApprovableTable.APPROVER, ctx.getRequestUser());
   record.set(ApprovableTable.APPROVED_AT, ctx.getRequestTime());

我知道这类似于 Postgres 继承功能,但我希望这个更独立于数据库,并希望在 Oracle 数据库中使用它。我想像配置 JOOQ 生成器并告诉它“这四个表属于一个逻辑组,我将其命名为“可批准”,它们都有列 APPROVERAPPROVED_AT。”这将让 JOOQ 生成类,例如为该组实现标记接口。

我认为在考虑历史记录、批准等常见任务、标记要删除的行等时,这可能是一个相当常用的功能。

我的问题:

JOOQ 中是否已经有一种方法可以实现我想要的类型安全结果? 有关如何以类型安全的方式处理此场景的任何其他建议? 或者我应该忘记这里的类型安全性?

【问题讨论】:

【参考方案1】:

使用 jOOQ 3.14 中的可嵌入对象

jOOQ 3.14 引入了"embeddable types",在代码生成器的基础上彻底解决了这个问题。你可以像这样定义一个嵌入:

<configuration>
  <generator>
    <database>
      <embeddables>
        <embeddable>
          <name>APPROVAL_INFORMATION</name>
          <fields>
            <field><expression>APPROVER</expression></field>
            <field><expression>APPROVED_AT</expression></field>
          </fields>
        </embeddable>
      </embeddables>
    </database>
  </generator>
</configuration>

(可以进行更具体的配置,the manual for details)。这将为您生成一个辅助EmbeddableRecord,格式为:

public class ApprovalInformationRecord
extends EmbeddableRecordImpl<ApprovalInformationRecord> 
    public ApprovalInformationRecord(
        String approver, LocalDateTime approvedAt
    )  /* ... */ 
    
    // Getters, setters

您可以在查询、投影等中使用此可嵌入列而不是基础列。例如

Result<Record2<Long, ApprovalInformationRecord>> result =
ctx.select(T.ID, T.APPROVAL_INFORMATION)
   .from(T)
   .where(T.APPROVAL_INFORMATION.eq(new ApprovalInformationRecord(...))
   .fetch();

使用自定义接口的通用解决方案

您可以轻松配置和扩展 jOOQ 代码生成器,为您添加类型信息。既然你想处理生成的记录,只需在你的代码库中添加一个这样的新接口:

public interface Approvable 
    void setApprover(String approver);
    void setApprovedAt(Timestamp approvedAt);

然后配置代码生成器,让所有相关的生成记录使用生成器策略实现上述接口:

Programmatic Configurative

一个配置示例:

..
<generator>
  <strategy>
    <matchers>
      <tables>
        <table>
          <expression>MY_TABLE</expression>
          <recordImplements>com.example.Approvable</recordImplements>
        </table>
      </tables>
    </matchers>
  </strategy>
</generator>

【讨论】:

有没有办法生成可用于所有可批准表的通用字段常量,就像 OP 提议的那样:ApprovableTable.APPROVED_AT @Sebastian:这和 OP 的问题是同一个问题吗?关于接口的问题?你的似乎是关于“常数”的——也许问一个新问题而不是细节?我很乐意在那里回答。 当然!你可以找到它here

以上是关于JOOQ:在通用界面中对来自不同表的列进行逻辑分组的主要内容,如果未能解决你的问题,请参考以下文章

需要在 tablix 的列中对表达式进行分组

在熊猫数据框中对重复的列 ID 进行分组

如何在熊猫中对没有聚合功能的列进行分组?

Oracle 11g 文本:复合域索引 - 对来自不同表的列进行过滤

JOOq:通用表的更新

我可以对表中的列进行逻辑重新排序吗?