jOOQ 在写入记录时尝试为 Identity 列写入值

问题描述 投票:0回答:2

我有一个简单的方法(使用jooq),基本上是这样做的:

MyObject myObject = ...;
MyObjectRecord myObjectRecord = MyConvertor.convertor(myObject);

DSLContext create = ...;
create.insertInto(Tables.MY_OBJECT)
      .set(myObjectRecord)
      .execute();

在表“MY_OBJECT”中,我有一个字段“id”,其定义为:

id SERIAL NOT NULL;

每当我运行上述代码时,都会收到错误:

Exception in thread "main" org.jooq.exception.DataAccessException: SQL [insert into "public"."myobject" ("somefield", "id") values (?, ?)];
ERROR: null value in column "id" violates not-null constraint
Failing row contains (somevalue, null).

在我看来,问题在于 jOOq 正在尝试将值写入标识列。

MyConvertor
将其保留为 null 的原因是因为该值将由数据库生成。我如何让 jooq 不尝试向该字段写入
null

postgresql jooq
2个回答
0
投票

我认为您想要做的不是通过

set
传递整个对象,而是明确定义想要的列和值
insert
,因为您只想
insert
其中的一个子集。

例如:

create.insertInto(Tables.MY_OBJECT, "somefield")
      .values(MyObjectRecord.getSomeField()).execute();

假设

MyObjectRecord
有一个
getSomeField
方法来检索该字段的值。

insertInto
的第一个参数是表名,后面是列名的可变参数列表。然后
values
接受列值的 vararg 列表。这允许您指定特定的列/值对,它们是整个对象的子集。

您也可以使用

set
样式,但将列/值对作为参数进行枚举,即:

create.insertInto(Tables.MY_OBJECT)
      .set("somefield", MyObjectRecord.getSomeField())
      .execute();

注意:未经测试,但我认为上述之一(或两者)应该有效。

编辑回应OP的评论:

好的...使用完全不包含

id
列的对象版本怎么样,这样它就不会被 jOOQ 使用?您也许可以拥有一个没有
id
列的基础对象,然后拥有一个派生对象,在需要时在顶部添加
id
列。


0
投票

我今天也遇到了同样的问题,找到了解决办法:可以打电话

reset(field)

MyObject myObject = ...;
MyObjectRecord myObjectRecord = MyConvertor.convertor(myObject);

// Tell jOOQ to not write the null value, which would violate the 'not null' constraint
myObjectRecord.reset(MY_OBJECT.ID);

DSLContext create = ...;
create.insertInto(Tables.MY_OBJECT)
      .set(myObjectRecord)
      .execute();

问题的根源是应用程序总是调用

set(MY_OBJECT.ID, idValueToSet)
,即使
idValueToSet
null
。由于 jOOQ 记录对象会跟踪调用了哪些 setter,这与 不调用
set()
不同:它会导致 jOOQ 在 INSERT(或 UPDATE)操作中包含该字段,从而导致 OP 遇到约束冲突。

但是请注意,虽然上面的方法解决了这个问题,但它并不是真正的最佳选择:这意味着代码的一部分(转换器类)总是调用

set()
,然后代码的另一部分(如图所示)上面)通过调用
reset()
来取消此操作。显然,最好更改转换器类以检查
null
并避免在这种情况下调用
set()

但这可能不适用于您的情况。这是一个例子:在我的例子中,转换器类应该直接映射事物,而不包含像这样的特殊情况,部分原因是它不仅用于

INSERT
,还用于
UPDATE
。所以我真的不想将“if null 避免调用 set”逻辑放入转换器类中,最终得到了上面所示的
reset()
解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.