Spring JDBC RowMapper with Class Hiearchies
-
11-09-2019 - |
質問
Spring JDBCのクラス階層をマッピングすることに関して、コミュニティが「ベストプラクティス」と見なしていることを知りたかったのです。
本格的なORMツールを使用する機能はありませんが、Spring JDBCを使用してJDBCの退屈な性質の一部を軽減しています。私たちが非常に定期的に活用しているクラスの1つは、それが使いやすさであり、結果セットからの卑劣なBeanプロパティアクセスを持つ能力のために、BeanPropertyrowMapperです。
すべてのテーブルに戻るクラスの階層があります(この小さなクラスの階層のために、テーブルあたりのテーブルアプローチを取得します)。そのため、テーブルには、実際にどのクラスをインスタンス化するかを決定するために使用できるClassID列が含まれています。元。 1 =マネージャー、2 =従業員、3 =請負業者。これらはすべて「人」ですが、人の各サブクラスには、クラスに固有のいくつかの属性があります。
私の最初の考えは、BeanPropertyRowMapperのサブクラスを作成し、このロジックを注入して「列a = 1の場合、マネージャーをインスタンス化してから、名前のバインディングを行う」と言うことです。
これは合理的なアプローチのように思えますか?人々があなたのために働いたかもしれない他の提案はありますか?
ご返信ありがとうございます、
ジャスティンN.
解決
サブクラスには、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;
}
}
};
他のヒント
「ベストプラクティス」であるかどうかはわかりませんが、次のアプローチをお勧めします(Beanプロパティを使用せずに、>より速く動作するはずです)。
通常、どのようなオブジェクトを取得するかを知っています。したがって、SQLを実行するときに対応する行マッパーを提供できます。
カスタムアブストラクトジェネリックロウマッパーを宣言し、各タイプの人に独自のrowマッパーを作成します。
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;
}