Java数据层次结构和行映射

时间:2015-01-07 15:25:06

标签: java spring inheritance jdbc

我有一个应用程序需要使用许多重复的行来建模一些现有的数据库表(我无法更改它们)。我试图找出一个好的设计来尽可能多地重用映射代码,所以我不必复制一堆set调用。

以下是两个表的示例。

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语句。

请告知。

1 个答案:

答案 0 :(得分:1)

我个人倾向于在处理这类数据时使用不可变对象。想象一下下面的课程:

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 - 对象。以这种方式使用时,您可以像这样设置RowMapper

// 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。但是,对于域模型,拥有某种基础对象(例如Identifiable)可能是有意义的。一个id(因为例如DepartmentEmployeeTimeAndExpense个对象似乎都包含一个id甚至可能是一个时间戳。)