【问题标题】:fields in JOOQ record not lining up when fetchIntofetchInto 时 JOOQ 记录中的字段未排列
【发布时间】:2019-04-13 09:56:33
【问题描述】:

这是一个奇怪的问题,在 JOOQ 的 3.10 和 3.11 版本中不断发生(没有尝试过早期版本)。我使用fetchInto 获取记录,当我打印记录(或进行调试)时,所有字段都正确打印。也就是说 field_x 的值是正确的。

问题是,当我使用记录的getX 方法检索field_x 时,它会从另一个字段返回值。

以下是我们使用的一些代码。

        return jooqDslContext.select(CL_USERS.fields())
            .from(CL_USERS)
            .join(THIRDPARTY_USER_XREF)
            .on(THIRDPARTY_USER_XREF.USER_ID.eq(CL_USERS.CL_USER_ID))
            .join(THIRDPARTY_USER_ID)
            .on(THIRDPARTY_USER_ID.ID.eq(THIRDPARTY_USER_XREF.THIRDPARTY_ID))
            .where(THIRDPARTY_USER_ID.EID.eq(eid))
            .fetchOptionalInto(CL_USERS);

这是记录的印刷品……

+--------------------------------------------------+----------+------+-----------+------------------+------------+----------------+------------------------+ etc... 
|remember_token                                    |cl_user_id|ria_id|ria_user_id|ria_user_id_backup|cl_user_type|user_description|first_name              | etc...
+--------------------------------------------------+----------+------+-----------+------------------+------------+----------------+------------------------+ etc...
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...| 777777777|   777|      77777|            {null}|      {null}|{null}          |xxxxxxxxxxxxxxxxxxxxxxxx| etc...
+--------------------------------------------------+----------+------+-----------+------------------+------------+----------------+------------------------

请注意 first_name 已填充。但是当我使用getFirstName 方法打印first_name 时,我得到NULL

cur.getFirstName() = null

看起来好像字段的索引号不匹配....生成的代码认为firstName是字段6,在这种情况下,但实际上它是字段8(第8个toString() 输出中的字段。

    public byte[] getFirstName() {
        return (byte[]) get(6);
    }

编辑:添加更多信息。

如何复制?

这是另一个使用与上例不同的代码库的示例。在这种情况下,我在记录对象上设置了amount 字段。但是当我去保存或打印出来时,address 字段被设置了。

    TransactionsRecord tr = serviceDslContext.newRecord(Transactions.TRANSACTIONS);
    tr.setAmount(new BigDecimal(10));
    logger.debug("tr = {}", tr);

打印..

+------+-------+-------+...
|amount|account|address|...
+------+-------+-------+...
|{null}|{null} |*10    |...
+------+-------+-------+...

Link to the JOOQ generated code.

你能发布表格的 DDL 吗?

CREATE TABLE `transactions` (
    `account` VARCHAR(50) NOT NULL,
    `address` VARCHAR(50) NOT NULL,
    `amount` DECIMAL(42,10) NOT NULL,
    `bip125-replaceable` VARCHAR(64) NOT NULL,
    `blockhash` VARCHAR(64) NOT NULL,
    `blockindex` INT(11) NOT NULL,
    `blocktime` TIMESTAMP NULL DEFAULT NULL,
    `category` VARCHAR(50) NOT NULL,
    `confirmation` INT(11) NOT NULL,
    `generated` TINYINT(1) NOT NULL,
    `instantlock` TINYINT(4) NOT NULL,
    `involvesWatchonly` TINYINT(4) NOT NULL,
    `label` VARCHAR(50) NOT NULL,
    `time` TIMESTAMP NULL DEFAULT NULL,
    `timereceived` TIMESTAMP NULL DEFAULT NULL,
    `txid` VARCHAR(64) NOT NULL,
    `vout` INT(11) NOT NULL,
    `walletconflicts` TEXT NULL,
    `amount_in_usd` DECIMAL(42,10) NULL DEFAULT NULL,
    `usd_exchange_rate` DECIMAL(42,10) NULL DEFAULT NULL,
    PRIMARY KEY (`txid`),
    INDEX `account_generated` (`account`, `generated`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;

您使用的是什么数据库产品和版本?

在上述情况下,我在 AWS RDS 上使用 MySQL 5.7.23。对于第一个示例,它是 AWS RDS 上 MySQL 5.6 的变体。另外,对于后一个例子,它发生在 5.7.14-google 上,我们最近迁移到 AWS。

【问题讨论】:

  • 生成的记录和生成的表是否不匹配? IE。记录引用的列是否与表一样多?
  • 记录有44个字段,表格有44列。这个周末我在一个单独的项目中也有这个,但在这种情况下,使用 DslContext 创建一个新记录,并使用 setFieldName 方法分配值。当我尝试存储记录时,列未与字段对齐。为了解决这个问题,我改用 set(FIELD, value) 方法来设置记录的值。
  • 听起来像是代码生成器中一个非常奇怪的边缘案例错误。这怎么能被复制?您可以发布表格的DDL吗?您使用的是什么数据库产品和版本?
  • @LukasEder 添加了更多信息。

标签: java jooq


【解决方案1】:

在做了一些测试之后,IntelliJ 中的Rearrange code 功能似乎弄乱了 JOOQ 生成的代码。这会对在生产环境中运行的代码产生可怕的后果。 Rearrange code 功能在“提交更改”窗口中显示为一个选项。

测试包括在Rearrange code 功能之前和之后运行测试。下面是代码。

    TransactionsRecord tr = serviceDslContext.newRecord(TRANSACTIONS);
    tr.setAmount(new BigDecimal(10));
    logger.debug("tr = {}", tr);

如果这段代码在Rearrange code特性之前执行,也就是在JOOQ生成代码之后,那么会显示如下...

 +-------+-------+------+...
|account|address|amount|...
+-------+-------+------+...
|{null} |{null} |   *10|...
+-------+-------+------+...

IntelliJ 在 JOOQ 生成的代码上执行Rearrange code后,这是输出...

+------+-------+-------+...
|amount|account|address|...
+------+-------+-------+...
|{null}|{null} |*10    |...
+------+-------+-------+...

这些值似乎停留在正确的位置,但这些值所代表的字段发生了变化。

【讨论】:

  • 伟大的发现!感谢您记录这一点。我还会向 IntelliJ 提出一个错误。这很严重。
【解决方案2】:

您发布的生成记录似乎是手动修改或使用某些后处理器修改的,或者是由自定义生成器生成的。很明显,生成的表(顺序正确):

public class Transactions extends TableImpl<TransactionsRecord> {

    ...

    public final TableField<TransactionsRecord, BigDecimal> AMOUNT = 
      createField("amount", org.jooq.impl.SQLDataType.DECIMAL(42, 10).nullable(false), this, "");

    public final TableField<TransactionsRecord, String> ACCOUNT = 
      createField("account", org.jooq.impl.SQLDataType.VARCHAR(50).nullable(false), this, "");

    public final TableField<TransactionsRecord, String> ADDRESS = 
      createField("address", org.jooq.impl.SQLDataType.VARCHAR(50).nullable(false), this, "");

    ...

...以及生成的记录:

public class TransactionsRecord extends UpdatableRecordImpl<TransactionsRecord> 
    implements Record20<...> {

    public void setAccount(String value) {
        set(0, value);
    }

    public String getAccount() {
        return (String) get(0);
    }

    public void setAddress(String value) {
        set(1, value);
    }

    public TransactionsRecord() {
        super(Transactions.TRANSACTIONS);
    }

    public TransactionsRecord(String account, String address, BigDecimal amount, ...) {
        super(Transactions.TRANSACTIONS);

        set(0, account);
        set(1, address);
        set(2, amount);
        ...
    }

    public BigDecimal getAmount() {
        return (BigDecimal) get(2);
    }

    public String getAddress() {
        return (String) get(1);
    }

    public void setAmount(BigDecimal value) {
        set(2, value);
    }

    public void setBlockhash(String value) {
        set(4, value);
    }

    ...

...不匹配。看看构造函数之后的 之前是如何有 getter 和 setter 的。此外,它们不按顺序排列! jOOQ提供的官方JavaGenerator不会生成这样的类。

注意,如果您确实想修改生成的代码,您应该覆盖 JavaGenerator 或实现您自己的生成器类。

【讨论】:

  • 哦,哇,我想知道它是不是由 IntelliJ 引起的?我只使用 JOOQ 生成器。但我知道当我提交代码时,IntelliJ 会重新格式化、重新排列、清理和优化导入……这些就是它拥有的各种 Before Commit 选项。
  • 要做一个新的生成,测试代码,然后应用 IntelliJ 的后处理器,并重现问题。
  • @JoseMartinez:但这只能解释不同的顺序,而不是 getter 和构造函数中使用的不同索引。
  • 我认为它比我们期望的 IDE 应该做的更多。我的猜测是重新排列代码功能是罪魁祸首。我使用的唯一生成器是 3.10 的 org.jooq.util.GenerationTool 或 3.11 的 org.jooq.codegen.GenerationTool。今晚我会得到我的测试结果。
  • 查看我发布的答案。
猜你喜欢
  • 2021-09-01
  • 1970-01-01
  • 2021-08-27
  • 2021-03-03
  • 2021-12-10
  • 2018-11-11
  • 1970-01-01
  • 2020-08-04
相关资源
最近更新 更多