PostgreSQL Upsert 使用记录
PostgreSQL Upsert Using Records
我目前正在尝试使用记录执行更新插入(使用 3.10 快照),并且注意到当我使用 addRecord(R)
时,更新的 set
数据没有添加到查询中。在 DAO 中我有:
try (Connection writeConn = DatabaseManager.getConnection(true);
final DSLContext writeContext = DatabaseManager.getBuilder(writeConn);
InsertQuery<UserProgramAssignmentsRecord> programAssignmentsUpdateQuery = writeContext
.insertQuery(AccessControlWriteDAO.userProgramAssignments)) {
programAssignmentsUpdateQuery.onDuplicateKeyUpdate(true);
programAssignments.forEach(pa -> programAssignmentsUpdateQuery.addRecord(pa.toRecord()));
if (!programAssignments.isEmpty()) {
if (AccessControlWriteDAO.logger.isInfoEnabled()) {
AccessControlWriteDAO.logger.info(writeContext.renderInlined(programAssignmentsUpdateQuery));
}
// programAssignmentsUpdateQuery.execute();
}
} catch (final SQLException e) {
throw new DAOException(e.getMessage(), e);
}
在 programAssignments 的 class 内部,我有:
/**
* <p>
* This method turns the object into a {@link Record} that can then be attached to a {@link Connection} and
* {@link DSLContext}.
* </p>
*
* @return A usable {@link UserProgramAssignmentsRecord}
*/
public UserProgramAssignmentsRecord toRecord() {
UserProgramAssignmentsRecord upar = new UserProgramAssignmentsRecord();
getAdministerProgram().ifPresent(upar::setAdminister);
getCreateProjects().ifPresent(upar::setCreateProjects);
getJustification().ifPresent(upar::setJustification);
getProgramId().ifPresent(upar::setProgramId);
getUserId().ifPresent(upar::setUserId);
getViewRevisions().ifPresent(upar::setViewRevisions);
return upar;
}
代码生成以下查询:
insert into "%%removed%%"."user_project_assignments" (
"project_id",
"edit_draft",
"justification",
"user_id"
)
values (
98332,
true,
'The user created the project',
675
)
on conflict (
"project_id",
"user_id"
) do update
set [ no fields are updated ]
我必须改用 addValue(Field<T>,T)
、addValueForUpdateField(Field<T>,T)
和 newRecord 吗?我会 认为 传递记录是等效的,但情况似乎并非如此,因为 addRecord(R)
似乎没有将字段设置为更新 - 或者- 我的 toRecord()
方法有问题吗? InsertQuery
对象有某种 addRecordForUpdate(R)
吗?这对多行更新插入有多有效(这是我正在尝试做的)?
查看文档后,我认为这有点……不足……虽然有人可能 认为 addRecord(R)
+ onDuplicateKeyUpdate(true)
将意味着更新数据设置为 或 会有一个 addValueForUpdate(R)
,这(显然)是错误的。我的解决方案是让我的 POJO 也有另一种方法 toExcludedMap()
,看起来像这样:
/**
* <p>
* This method returns mappings that can be used in an UPSERT in the update portion of the query.
* </p>
*
* @return A map between the assignments table and the excluded table
*/
public Map<Field<?>, Field<?>> toExcludedMap() {
final UserProgramAssignments excludedTable = UserProgramAssignment.pua.as("excluded");
final Map<Field<?>, Field<?>> excludedMap = new HashMap<>(4);
getAdministerProgram()
.ifPresent(i -> excludedMap.put(UserProgramAssignment.pua.ADMINISTER, excludedTable.ADMINISTER));
getCreateProjects().ifPresent(
i -> excludedMap.put(UserProgramAssignment.pua.CREATE_PROJECTS, excludedTable.CREATE_PROJECTS));
getJustification()
.ifPresent(i -> excludedMap.put(UserProgramAssignment.pua.JUSTIFICATION, excludedTable.JUSTIFICATION));
getViewRevisions().ifPresent(
i -> excludedMap.put(UserProgramAssignment.pua.VIEW_REVISIONS, excludedTable.VIEW_REVISIONS));
return excludedMap;
}
然后我将我的 DAO 调整为这样:
try (Connection writeConn = DatabaseManager.getConnection(true);
final DSLContext writeContext = DatabaseManager.getBuilder(writeConn);
InsertQuery<UserProgramAssignmentsRecord> programAssignmentsUpdateQuery = writeContext
.insertQuery(AccessControlWriteDAO.userProgramAssignments)) {
programAssignmentsUpdateQuery.onDuplicateKeyUpdate(true);
programAssignments
.forEach(assignment -> AccessControlWriteDAO.addRecordToUpsert(programAssignmentsUpdateQuery,
assignment.toRecord(), assignment.toExcludedMap()));
if (!programAssignments.isEmpty()) {
if (AccessControlWriteDAO.logger.isInfoEnabled()) {
AccessControlWriteDAO.logger.info(writeContext.renderInlined(programAssignmentsUpdateQuery));
}
programAssignmentsUpdateQuery.execute();
}
} catch (final SQLException e) {
throw new DAOException(e.getMessage(), e);
}
然后,为了保持干净,我创建了一个更新 InsertQuery 的新方法:
/**
* <p>
* This method is used to add a record and the update information to an UPSERT query.
* </p>
*
* @param query
* The query to add to
* @param record
* The record to add
* @param excludedMap
* The mappings to the "excluded" table for this record
*/
private static <R extends Record> void addRecordToUpsert(final InsertQuery<R> query, final R record,
final Map<Field<?>, Field<?>> excludedMap) {
query.addRecord(record);
query.addValuesForUpdate(excludedMap);
}
有点糟透了,我们没有对称性,我 1) 必须制作地图,2) 必须再次调用方法来获取数据在 但 我相信这是目前唯一的方法。如果 jOOQ 添加更新数据或至少记录并排除 PK 会很好(因为如果我们更新重复键,显然 PK 没有改变),但也许这是不可能的。
我目前正在尝试使用记录执行更新插入(使用 3.10 快照),并且注意到当我使用 addRecord(R)
时,更新的 set
数据没有添加到查询中。在 DAO 中我有:
try (Connection writeConn = DatabaseManager.getConnection(true);
final DSLContext writeContext = DatabaseManager.getBuilder(writeConn);
InsertQuery<UserProgramAssignmentsRecord> programAssignmentsUpdateQuery = writeContext
.insertQuery(AccessControlWriteDAO.userProgramAssignments)) {
programAssignmentsUpdateQuery.onDuplicateKeyUpdate(true);
programAssignments.forEach(pa -> programAssignmentsUpdateQuery.addRecord(pa.toRecord()));
if (!programAssignments.isEmpty()) {
if (AccessControlWriteDAO.logger.isInfoEnabled()) {
AccessControlWriteDAO.logger.info(writeContext.renderInlined(programAssignmentsUpdateQuery));
}
// programAssignmentsUpdateQuery.execute();
}
} catch (final SQLException e) {
throw new DAOException(e.getMessage(), e);
}
在 programAssignments 的 class 内部,我有:
/**
* <p>
* This method turns the object into a {@link Record} that can then be attached to a {@link Connection} and
* {@link DSLContext}.
* </p>
*
* @return A usable {@link UserProgramAssignmentsRecord}
*/
public UserProgramAssignmentsRecord toRecord() {
UserProgramAssignmentsRecord upar = new UserProgramAssignmentsRecord();
getAdministerProgram().ifPresent(upar::setAdminister);
getCreateProjects().ifPresent(upar::setCreateProjects);
getJustification().ifPresent(upar::setJustification);
getProgramId().ifPresent(upar::setProgramId);
getUserId().ifPresent(upar::setUserId);
getViewRevisions().ifPresent(upar::setViewRevisions);
return upar;
}
代码生成以下查询:
insert into "%%removed%%"."user_project_assignments" (
"project_id",
"edit_draft",
"justification",
"user_id"
)
values (
98332,
true,
'The user created the project',
675
)
on conflict (
"project_id",
"user_id"
) do update
set [ no fields are updated ]
我必须改用 addValue(Field<T>,T)
、addValueForUpdateField(Field<T>,T)
和 newRecord 吗?我会 认为 传递记录是等效的,但情况似乎并非如此,因为 addRecord(R)
似乎没有将字段设置为更新 - 或者- 我的 toRecord()
方法有问题吗? InsertQuery
对象有某种 addRecordForUpdate(R)
吗?这对多行更新插入有多有效(这是我正在尝试做的)?
查看文档后,我认为这有点……不足……虽然有人可能 认为 addRecord(R)
+ onDuplicateKeyUpdate(true)
将意味着更新数据设置为 或 会有一个 addValueForUpdate(R)
,这(显然)是错误的。我的解决方案是让我的 POJO 也有另一种方法 toExcludedMap()
,看起来像这样:
/**
* <p>
* This method returns mappings that can be used in an UPSERT in the update portion of the query.
* </p>
*
* @return A map between the assignments table and the excluded table
*/
public Map<Field<?>, Field<?>> toExcludedMap() {
final UserProgramAssignments excludedTable = UserProgramAssignment.pua.as("excluded");
final Map<Field<?>, Field<?>> excludedMap = new HashMap<>(4);
getAdministerProgram()
.ifPresent(i -> excludedMap.put(UserProgramAssignment.pua.ADMINISTER, excludedTable.ADMINISTER));
getCreateProjects().ifPresent(
i -> excludedMap.put(UserProgramAssignment.pua.CREATE_PROJECTS, excludedTable.CREATE_PROJECTS));
getJustification()
.ifPresent(i -> excludedMap.put(UserProgramAssignment.pua.JUSTIFICATION, excludedTable.JUSTIFICATION));
getViewRevisions().ifPresent(
i -> excludedMap.put(UserProgramAssignment.pua.VIEW_REVISIONS, excludedTable.VIEW_REVISIONS));
return excludedMap;
}
然后我将我的 DAO 调整为这样:
try (Connection writeConn = DatabaseManager.getConnection(true);
final DSLContext writeContext = DatabaseManager.getBuilder(writeConn);
InsertQuery<UserProgramAssignmentsRecord> programAssignmentsUpdateQuery = writeContext
.insertQuery(AccessControlWriteDAO.userProgramAssignments)) {
programAssignmentsUpdateQuery.onDuplicateKeyUpdate(true);
programAssignments
.forEach(assignment -> AccessControlWriteDAO.addRecordToUpsert(programAssignmentsUpdateQuery,
assignment.toRecord(), assignment.toExcludedMap()));
if (!programAssignments.isEmpty()) {
if (AccessControlWriteDAO.logger.isInfoEnabled()) {
AccessControlWriteDAO.logger.info(writeContext.renderInlined(programAssignmentsUpdateQuery));
}
programAssignmentsUpdateQuery.execute();
}
} catch (final SQLException e) {
throw new DAOException(e.getMessage(), e);
}
然后,为了保持干净,我创建了一个更新 InsertQuery 的新方法:
/**
* <p>
* This method is used to add a record and the update information to an UPSERT query.
* </p>
*
* @param query
* The query to add to
* @param record
* The record to add
* @param excludedMap
* The mappings to the "excluded" table for this record
*/
private static <R extends Record> void addRecordToUpsert(final InsertQuery<R> query, final R record,
final Map<Field<?>, Field<?>> excludedMap) {
query.addRecord(record);
query.addValuesForUpdate(excludedMap);
}
有点糟透了,我们没有对称性,我 1) 必须制作地图,2) 必须再次调用方法来获取数据在 但 我相信这是目前唯一的方法。如果 jOOQ 添加更新数据或至少记录并排除 PK 会很好(因为如果我们更新重复键,显然 PK 没有改变),但也许这是不可能的。