Java 数据层次结构和行映射

Java Data Hierarchy and Row Mapping

我有一个应用程序需要用一些重复的行对一些现有的数据库表(我无法更改它们)进行建模。我正在尝试找出一个好的设计来尽可能多地重用映射代码,这样我就不必重复一堆设置调用。

这是其中两个表格的示例。

TIME_AND_EXPENSE_STAGING

Name               Null     Type           
------------------ -------- -------------- 
SEQ_NUM            NOT NULL NUMBER(31)     
DATETIME_STAMP              TIMESTAMP(6)   
DEPT_ID            NOT NULL VARCHAR2(10)   
EMPL_ID            NOT NULL VARCHAR2(11)   
JOB_CODE           NOT NULL VARCHAR2(6)    
REGULAR_HRS        NOT NULL NUMBER(4,2)    
OVERTIME_HRS       NOT NULL NUMBER(4,2)    
MILES              NOT NULL NUMBER(8,2)    
COMMENTS           VARCHAR2(4000) 

TIME_AND_EXPENSE_APPROVED

Name               Null     Type           
------------------ -------- -------------- 
SEQ_NUM            NOT NULL NUMBER(31)     
DATETIME_STAMP              TIMESTAMP(6)   
DEPT_ID            NOT NULL VARCHAR2(10)   
EMPL_ID            NOT NULL VARCHAR2(11)   
JOB_CODE           NOT NULL VARCHAR2(6)    
REGULAR_HRS        NOT NULL NUMBER(4,2)    
OVERTIME_HRS       NOT NULL NUMBER(4,2)    
MILES              NOT NULL NUMBER(8,2)    
COMMENTS           VARCHAR2(4000)     
APPROVE_TIME       NOT NULL TIMESTAMP(6)
APPROVER_ID        NOT NULL VARCHAR2(11)

我正在使用 Spring 框架和 Spring RowMapper 来填充数据对象。我觉得应该有一些优雅的方式来使用继承或多态性或一些设计模式来防止我不得不复制和粘贴一堆 set 语句。

请指教

在处理这类数据时,我个人倾向于使用不可变对象。想象以下 class:

public class TimeAndExpense {
    private final String jobCode;
    // and a bunch of other attributes such as department...

    // Then the additional data (approval data)
    private final Optional<String> approverId;
    private final Optional<Timestamp> approveTime;

    public TimeAndExpense(final String jobCode) {
        this(jobCode, null, null);
    }

    public TimeAndExpense(
                final String jobCode, 
                final Timestamp approveTime, 
                final String approverId) {

        this.jobCode = jobCode;
        // And the rest of the attributes...

        this.approveTime = Optional.ofNullable(approveTime);
        this.approverId = Optional.ofNullable(approverId);
    }

    public Optional<Timestamp> getApproveTime() {
        return approveTime;
    }

    public Optional<String> getApproverId() {
        return approverId;
    }

    public String getJobCode() {
        return jobCode;
    }

    public boolean isApproved() {
        return approverId.isPresent();
    }

    // Creates a new object with the approval data (immutable)
    public TimeAndExpense withApprovalData(final Timestamp approveTime, final String approverId) {
        return new TimeAndExpense(this.getJobCode(), approveTime, approverId);
    }
}

方法 withApprovalData 可用于创建具有附加批准数据的 TimeAndExpense 对象。以这种方式使用时,您可以像这样设置 RowMappers:

// The RowMapper for the table TIME_AND_EXPENSE_STAGING
// More columns than JOB_CODE exists but are not part of the example
private final RowMapper<TimeAndExpense> timeAndExpenseRowMapper = 
        (rs, rowNum) -> new TimeAndExpense(rs.getString("JOB_CODE"));

// The RowMapper for the table TIME_AND_EXPENSE_APPROVED
// Reuse the timeAndExpenseRowMapper's mapping, then add additional approval data
private final RowMapper<TimeAndExpense> timeAndExpenseApprovedRowMapper =
        (rs, rowNum) -> timeAndExpenseRowMapper
                .mapRow(rs, rowNum) // use the timeAndExpenseRowMapper
                .withApprovalData(  // and add the additional approval data
                        rs.getTimestamp("APPROVE_TIME"),
                        rs.getString("APPROVER_ID"));

这种委派(一个 RowMapper 使用另一个 RowMapper)在表非常相似并且可以实现大量代码重用时效果很好。

继承是我个人尽量少用的东西in favour of composition。但是,对于域模型来说,拥有某种包含例如一个 id(因为例如 DepartmentEmployeeTimeAndExpense 对象似乎都包含一个 id,甚至可能是一个时间戳)。