2017-06-29 62 views
0

我正在嘗試使用記錄執行upsert(使用3.10快照),並且注意到當我使用addRecord(R)時,更新的set數據未被添加到查詢中。在DAO我:PostgreSQL Upsert使用記錄

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的,我有:

/** 
* <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)?這對多行upserts(這是我想要做的)有多好?

回答

0

審查文件後,我覺得這是一個有點......缺乏....雖然人們可能會認爲 + addRecord(R)onDuplicateKeyUpdate(true)意味着,更新數據設置會有一個(顯然)是錯的。我的解決辦法是讓我的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沒有改變),但這可能是不可能的。