我有一个简单的方法(使用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
?
我认为您想要做的不是通过
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
列。
我今天也遇到了同样的问题,找到了解决办法:可以打电话
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()
解决方案。