【问题标题】:Spring JDBC RowMapper with Class Hierarchies具有类层次结构的 Spring JDBC RowMapper
【发布时间】:2010-12-22 12:05:47
【问题描述】:

我想知道社区认为关于使用 Spring JDBC 映射类层次结构的“最佳实践”。

我们没有能力使用成熟的 ORM 工具,但是我们正在使用 Spring JDBC 来减轻 JDBC 的一些繁琐性质。我们经常使用的一类是 BeanPropertyRowMapper,因为它易于使用,并且能够从我们的结果集中访问类型不敏感的 bean 属性。

我有一个类层次结构,它全部映射回单个表(对这个小类层次结构采用 table-per-hiearchy 方法)。因此,该表包含一个 classId 列,可用于确定应实际实例化的类。前任。 1 = 经理,2 = 员工,3 = 承包商。所有这些都是“人”,但每个人的子类都有一些属性是他们的类所独有的。

我最初的想法是创建一个 BeanPropertyRowMapper 的子类,并尝试注入此逻辑来表示“如果列 A = 1,则实例化一个 Manager,然后进行正常绑定”。

这看起来是一种合理的方法吗?是否还有其他对您有用的建议?

【问题讨论】:

    标签: java spring orm class-hierarchy spring-jdbc


    【解决方案1】:

    我不确定这是“最佳实践”,但我建议采用以下方法(不使用 bean 属性 --> 应该更快)。

    通常你知道你期望检索什么样的对象。所以在执行sql的时候可以提供相应的row mapper。

    声明自定义抽象泛型 RowMapper 并为每种类型的人创建自己的行映射器,即:

    private static abstract class PersonRowMapper<T extends Person> implements RowMapper<T> {
    
     @Override
     public abstract T mapRow(ResultSet rs, int rowNum) throws SQLException;
    
     protected void mapBase(ResultSet rs, T person) throws SQLException {
      //base mapping here
     }
    }
    
    
    private static class EmployeeRowMapper extends PersonRowMapper<Employee> {
    
     @Override
     public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
      Employee e = new Employee();
      mapBase(rs, e);
      //set other specific employee props
     }
    }
    

    通过其他方法,您可以在基本映射器中为特定道具声明抽象方法,即

    private static abstract class PersonRowMapper<T extends Person> implements RowMapper<T> {
     @Override
     public T mapRow(ResultSet rs, int rowNum) throws SQLException {
      T instance = getInstance();
      //set base props here
      fill(rs, instance);
     }
    
     //e.g. return new Employee()
     protected abstract T getInstance();
     //fill specific instance props
     protected abstract void fill(ResultSet rs, T instance) throws SQLException;
    }
    

    【讨论】:

      【解决方案2】:

      在子类中似乎没有一个地方可以添加一个钩子来切换类,而无需完全复制 BeanPropertyRowMapper 的 mapRow() 实现。您最好的方法可能是创建一个 RowMapper 类,该类委托给适当的 BeanPropertyRowMapper。

      例如:

          final RowMapper managerMapper = new BeanPropertyRowMapper(Manager.class);
          final RowMapper employeeMapper = new BeanPropertyRowMapper(Employee.class);
          final RowMapper contractorMapper = new BeanPropertyRowMapper(Contractor.class);
      
          RowMapper rm = new RowMapper()
          {
              @Override
              public Object mapRow(ResultSet rs, int rowNum)
                  throws SQLException
              {
                  int employeeType = rs.getInt("type");
                  switch (employeeType)
                  {
                      case 1:
                          return managerMapper.mapRow(rs, rowNum); 
      
                      case 2:
                          return employeeMapper.mapRow(rs, rowNum);
      
                      case 3:
                          return contractorMapper.mapRow(rs, rowNum);
      
                      default:
                          break;
      
                  }
              }
          };
      

      【讨论】:

      • 感谢您的回复。这就是我最终所做的!很高兴得到一些验证。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-07
      相关资源
      最近更新 更多