Весенний JDBC RowMapper с классом Hiearchies - PullRequest
5 голосов
/ 02 декабря 2009

Я хотел знать, что сообщество считает «лучшими практиками» в отношении отображения иерархий классов с помощью Spring JDBC.

У нас нет возможности использовать полноценный инструмент ORM, однако мы используем Spring JDBC для облегчения некоторых утомительных действий JDBC. Одним из классов, который мы используем очень регулярно, является BeanPropertyRowMapper за его простоту использования и возможность иметь доступ к свойствам бина, не зависящих от типа, из нашего набора результатов.

У меня есть иерархия классов, которая все отображается обратно в одну таблицу (используя подход «таблица-на-иерархию» для этой небольшой иерархии классов). Таким образом, таблица содержит столбец classId, который можно использовать для определения того, какой класс должен быть фактически создан. Ex. 1 = менеджер, 2 = работник, 3 = подрядчик. Все это «Люди», но у каждого подкласса человека есть несколько атрибутов, которые уникальны для их класса.

Моя первоначальная мысль - создать подкласс BeanPropertyRowMapper и попытаться внедрить эту логику, чтобы сказать «если столбец A = 1, то создать экземпляр Manager и затем выполнить вашу номинальную привязку».

Это похоже на разумный подход? Есть ли какие-нибудь другие предложения, которые могли бы работать на вас?

Заранее спасибо за ваши ответы,

Джастин Н.

Ответы [ 2 ]

4 голосов
/ 02 декабря 2009

Не похоже, что в подклассе есть место, где вы могли бы добавить ловушку для переключения класса без полного копирования реализации mapRow () для BeanPropertyRowMapper. Наилучшим подходом может быть создание класса 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;

            }
        }
    };
1 голос
/ 11 ноября 2014

Я не уверен, что это «лучшая практика», но я предлагаю следующий подход (без использования свойств 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;
}
...