我想从一个表中选择所有字段,提取到另一个表的记录中,然后将记录插入该表中。但是,我得到一个错误,说值是空的。这是相关的代码段:
// Fetch PersonDeactivatedRecord person = getContext().selectFrom(PERSON) .where(PERSON.ID.eq(id)) .fetchOneInto(PersonDeactivatedRecord.class); // Insert person.setDeactivatedOn(new Timestamp(System.currentTimeMillis())); getContext().insertInto(PERSON_DEACTIVATED) .set(person) .execute();
该person_deactivated表是表的副本,person外加一列(deactivated_on)。我得到的错误是这样的:
person_deactivated
person
org.jooq.exception.DataAccessException: SQL [insert into "xxx"."person_deactivated" ("deactivated_on") values (cast(? as timestamp))]; ERROR: null value in column "id" violates not-null constraint Detail: Failing row contains (null, null, null, null, null, null, null, null, null, ...)
请注意,当我调试此代码时,我看到该person对象已按预期完全填充。知道我在这里缺少什么吗?
该InsertSetStep.set(Record)方法不会将整个person记录插入到目标表中,而是仅考虑值被“更改”的那些字段。参见Javadoc:
InsertSetStep.set(Record)
这set(Map)与将参数记录视为a的调用相同Map<Field<?>, Object>,不同之处在于Record.changed()考虑这些标志以便仅更新更改的值。
set(Map)
Map<Field<?>, Object>
Record.changed()
因此,您可以通过多种方式解决此问题(当然,这里列出的内容比我列出的还要多):
这将是最简单的解决方法:
// Insert person.setDeactivatedOn(new Timestamp(System.currentTimeMillis())); person.changed(true); // Sets all flags to true getContext().insertInto(PERSON_DEACTIVATED) .set(person) .execute();
该解决方案的优点是您只有一个查询,这意味着:
因此,您可以编写:
getContext() .insertInto(PERSON_DEACTIVATED) .columns(PERSON_DEACTIVATED.fields()) .select( select(Arrays .stream(PERSON_DEACTIVATED.fields()) .map(f -> f.equals(PERSON_DEACTIVATED.DEACTIVATED_ON) ? currentTimestamp() : PERSON.field(f)) .collect(Collectors.toList())) .from(PERSON) .where(PERSON.ID.eq(id)) ) .execute();
与往常一样,此答案假定您的代码中包含以下静态导入:
import static org.jooq.impl.DSL.*;
上述查询将插入所有列从PERSON成PERSON_DEACTIVATED,除了DEACTIVATED_ON列将通过当前的时间戳来代替。
PERSON
PERSON_DEACTIVATED
DEACTIVATED_ON