PostgreSQL Upsert使用记录

时间:2017-06-29 13:35:03

标签: java sql jooq

我目前正在尝试使用记录执行upsert(使用3.10-snapshot),并注意到当我使用{{{{}}}时,更新的set数据未被添加到查询中1}}。在DAO我有:

addRecord(R)

在programAssignments的类中,我有:

    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);
    }

代码生成以下查询:

/**
 * <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)和newRecord?我会思考传递记录是等价的,但似乎并非如此,addValueForUpdateField(Field<T>,T)似乎没有设置要更新的字段 - 或者 - 我在addRecord(R)方法中做错了什么? toRecord()addRecordForUpdate(R)对象是否有某种?这对于多行upserts有多好(这是我尝试做的事情)?

1 个答案:

答案 0 :(得分:0)

在审核文档后,我认为这有点......缺点......虽然有人可能认为 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没有改变)会很好,但也许这不是&# 39; t possible。