【问题标题】:Generating multiple java Enums from a single table, using JOOQ使用 JOOQ 从单个表生成多个 java 枚举
【发布时间】:2015-10-02 10:58:43
【问题描述】:

我的数据库架构中有一个表,其中包含我正在构建的应用程序的配置信息。我想根据表的内容生成一些枚举。我目前在我的构建脚本中使用 JOOQ 从同一个数据库生成其他标准 JOOQ 类,并希望我可以通过 JOOQ 获得这个新功能。

例如,如果表包含以下数据

Product        Component    PresentationOrder
HydroProduct   Boat         1
HydroProduct   Canoe        2
HyrdoProduct   Ship         3
LandProduct    Car          1
LandProduct    Bike         2

然后我想生成两个枚举

hydroProduct.Components { Boat, Canoe, Ship; }

landProduct.Components {Car, Bike; }

其中hydroProduct 和landProduct 是包,枚举都称为组件。

确切的细节有待商榷(例如,我可以使用不同的命名约定,因此欢迎提出任何建议),但原则(一个表中的两个枚举,基于其中的数据)至少是对于这个问题,我需要的东西。

阅读了 JOOQ 文档后,我发现生成枚举曾经是 JOOQ 的一部分,然后被删除了。我看不到在 JOOQ 中做我想做的事情的“明显”方式,但它是一个非常了不起的库,所以我猜可能会有一个。

编辑

许多评论者对整体方法提出了质疑,我理解这一点。我想避免这种对话——我基本上不可能在这个论坛上讨论这种设计水平。这种方法(基于 DDL 和 SQL 的代码生成)在我的组织中经过了很好的测试,并且经过了大量的设计审查。

只是为了记录,这里是管道的轮廓。我把它放进去是因为我很感激人们花时间考虑我最初的问题,我想说明这个问题如何适合我们的整体开发系统。

Project One 包含一些引导类、一些 DDL 和一些 SQL 脚本,其中包含我们整个系统使用的数据常量。它的输出包括(以及其他内容),一些 .jar 文件,其中包含生成的类的编译版本。这些基本上构成了我们系统其余部分用来交流的核心商定词汇。

项目二拥有java源代码,它利用了项目一生成的各种人工制品。在项目二被编译之前,可以假设项目一的人工制品已经生成。因此,例如,从项目 1 中保存的数据生成的 Enum 可以在编译时用于项目 2。

我们的构建脚本构建项目一,并使输出可用于项目二。这包括生成 Eclipse 项目文件,以便项目 2 的用户可以为项目的任何分支签出、构建和打开 Eclipse,并且它“正常工作”。

还有其他项目(包括不同的语言,例如 Javascript)也使用项目一生成的人工制品。

这种方法的主要好处是,当项目一中的数据发生变化时,项目一中的类和枚举的定义因此发生变化,项目二会通过编译时错误而不是运行时错误来反映这种变化.这在实践中的好处绝对是巨大的。是的,有一个设置成本,但在我们的经验中,像 JOOQ(我们用来生成项目 1 的输出)这样的工具使我们比以前更有效率。

在我们发布桌面、浏览器内和 J2EE 组件并且它们都需要一起交流的情况下尤其如此。

【问题讨论】:

  • enums 应该是编译时常量,因此根据数据库中的数据生成它们是 IMO 有问题的;如果有人在您发布软件后插入新值或删除现有值怎么办?
  • @Mick:在某些时候,必须决定规范常量的定义位置。 DDL 与 Java 文件一样是我的源代码的一部分。由于我已经从 DB 中生成了一堆 Java 类,然后进行了编译,因此数据库位于我的 Java 源代码的“上游”——所以我在数据库中定义了这些常量。如果有人在数据库中添加或删除现有行,则数据库和代码不再兼容。如果有人向源中的枚举添加一个常量,这也是正确的。
  • 我可以理解 DDL 是“源的一部分”,因为它描述了表的 结构。但是,我认为实际的 data 应该区别对待;如果给定表中的数据不应该在您的软件版本之间发生变化,那么当您可以将其存储在属性文件中时,为什么还要将其保存在数据库中?
  • 你的观点是完全正确的。我做出了我做出的选择,因为我判断 (a) 数据库和 Java 源代码必须就一组常量达成一致,(b) 编码该协议的最佳方法是将它们编码为数据库中的数据和枚举在 Java 中,(c) 数据库是我所知道的管理数据的最佳工具。有了这三个假设(它们只是我的假设),最好的做法是使用数据库来定义常量,并在 Java 中派生枚举。添加第三个位置来定义常量(如属性文件)对我来说吸引力不大。
  • @MickMnemonic:这当然有助于区分“普通数据”和“主数据”,后者更接近于元数据 (DDL) 而不是用户数据。当然,这是一条细线,但假设主数据很少更改,就像 DDL...

标签: java jooq


【解决方案1】:

这不会是一个详尽的答案,因为这个问题有点自以为是,但我可以提供一些关于 jOOQ 中此功能历史的权威背景:

阅读了 JOOQ 文档后,我发现生成枚举曾经是 JOOQ 的一部分,然后被删除了。

是的,删除的原因正是因为当时存在的实现远不够复杂,无法适应例如您的特定用例。

代码生成是一门非常特殊的“科学”,要向后兼容维护一个配置 API 非常困难,它可以适应所有可能的用例......例如,您想要映射零件的事实将您的主数据复制到包中,类名是不变的,自定义排序是相当特殊的,而不是通用的。

此外,应该从哪里引用生成的枚举?原始实现用生成代码中的枚举引用替换了外键(例如整数)。在某些情况下,这可能根本不是您想要的,您确实希望以原始形式加入主数据,而不是作为生成的枚举。

长话短说,这是 jOOQ 1.x 中急切添加的一个特性,在创建 jOOQ 3.x 所需的主要内部重构期间极难维护,which is why it was dropped

我看不到在 JOOQ 中做我想做的事情的“明显”方式,但它是一个非常了不起的库,所以我猜可能会有一个。

不是开箱即用的。我建议使用VelocityXtend 之类的模板语言,并在构建过程中手动生成代码。事实上,您甚至可以生成自定义的 Converter or Binding 实现来将您的枚举绑定到相关的引用列。

【讨论】:

  • 感谢您的参考。您会看到 Velocity 和/或 Xtend 位于 JOOQ 的上游还是下游? (我猜是下游,以便 Velocity/Xtend 生成的类可以引用 JOOQ 生成的类...?无论如何,谢谢大家。
  • 实际上,进一步考虑这一点,我认为您必须是指上游,因为它们可以用于绑定。 (我也不确定你上面第一句话是什么意思——固执己见?但谢谢你的背景。)
  • @BurleighBear:"Opinionated" as according to the faqs,即可能的答案是无穷无尽的。无论如何,在 jOOQ 类之前或之后生成这些枚举并不重要,但您可能必须同时编译它们。或者我错过了什么?
  • 感谢您的澄清。我不认为你缺少任何东西。我的意思是,在运行 jOOQ 以生成类时,我可能想在 jOOQ 的绑定定义中引用生成的枚举,所以我假设我必须在运行 jOOQ 之前编译枚举。 (我可能错了......)
  • @BurleighBear:啊哈,我明白了。不,您不必为此担心。 jOOQ 的代码生成器只生成恰好以.java 结尾的文本文件。编译在稍后发生,独立于 jOOQ 的代码生成器(或您的枚举生成器)
猜你喜欢
  • 2018-03-07
  • 2021-01-04
  • 2020-01-07
  • 1970-01-01
  • 1970-01-01
  • 2021-07-11
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
相关资源
最近更新 更多