具有类层次结构的 Spring JDBC RowMapper

发布于 2024-08-13 15:56:53 字数 470 浏览 15 评论 0原文

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

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

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

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

这看起来是一个合理的方法吗?人们还有其他对你有用的建议吗?

I wanted to know what the community considers the "best practices" in respect to mapping class hierarchies with Spring JDBC.

We do not have the ability to use a full fledged ORM tool, however we are using the Spring JDBC to alleviate some of the tedious nature of JDBC. One class which we leverage very regularly are the BeanPropertyRowMapper for it's ease of use and the ability to have type insensitive bean property access from our result set.

I have a class hierarchy that all maps back to a single table (taking the table-per-hiearchy approach for this small class hierarchy). As such, the table contains an classId column which can be used to determine what class should actually be instantiated. Ex. 1 = Manager, 2 = Employee, 3 = Contractor. All of these are "People" but each subclass of person has a few attributes which are unique to their class.

My initial thought is to create a subclass of BeanPropertyRowMapper and try and inject this logic to say "if column A = 1 then instantiate a Manager and then do your nomral binding".

Does this seem like a reasonable approach? Are there any other suggestions people may have that have worked for you?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

街角迷惘 2024-08-20 15:56:53

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

例如:

    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;

            }
        }
    };

It doesn't look like there's a place in the subclass where you could add a hook to switch the class without completely copying the implementation of mapRow() for BeanPropertyRowMapper. Your best approach might be to create a RowMapper class that delegates to the appropriate BeanPropertyRowMapper.

For example:

    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;

            }
        }
    };
盛夏尉蓝 2024-08-20 15:56:53

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

通常您知道您期望检索什么类型的对象。所以你可以在执行sql时提供相应的行映射器。

声明自定义抽象通用 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;
}

I'm not sure it's the 'best practice' but i suggest the following approach (without using bean properties --> should work faster).

Usually you know what kind of object you expect to retrieve. So you can provide corresponding row mapper when execute the sql.

Declare custom abstract generic RowMapper and create own row mapper for each type of person, i.e.:

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

By other approach you can declare abstract method in base mapper for specific props, i.e.

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文