2009-12-02 4 views
5

Je voulais savoir ce que la communauté considère comme les «meilleures pratiques» en matière de mappage des hiérarchies de classes avec Spring JDBC.Spring JDBC RowMapper avec Class Hiearchies

Nous n'avons pas la possibilité d'utiliser un outil ORM complet, mais nous utilisons le Spring JDBC pour alléger la nature fastidieuse de JDBC. Une classe que nous utilisons très régulièrement est le BeanPropertyRowMapper pour sa facilité d'utilisation et la possibilité d'avoir un accès aux propriétés bean insensible à la forme à partir de notre jeu de résultats.

J'ai une hiérarchie de classes qui toutes mappent à une seule table (en prenant l'approche table-par-hiérarchie pour cette hiérarchie de petite classe). En tant que tel, la table contient une colonne classId qui peut être utilisée pour déterminer quelle classe devrait être instanciée. Ex. 1 = Gestionnaire, 2 = Employé, 3 = Entrepreneur. Toutes ces personnes sont des «personnes», mais chaque sous-classe de la personne a quelques attributs qui sont uniques à leur classe. Ma première pensée est de créer une sous-classe de BeanPropertyRowMapper et d'essayer d'injecter cette logique pour dire "si la colonne A = 1 puis instancier un gestionnaire, puis faire votre lien nominal".

Est-ce que cela vous semble une approche raisonnable? Y a-t-il d'autres suggestions que les gens ont pu faire pour vous?

Merci d'avance pour vos réponses,

Justin N.

Répondre

4

Il ne semble pas comme il y a une place dans la sous-classe où vous pouvez ajouter un crochet pour passer la classe sans copier complètement la mise en œuvre de mapRow() pour BeanPropertyRowMapper. Votre meilleure approche pourrait être de créer une classe RowMapper qui délègue au BeanPropertyRowMapper approprié.

Par exemple:

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; 

      } 
     } 
    }; 
+0

Merci pour la réponse. C'est ce que j'avais fini par faire! Bon pour obtenir une validation. – jnt30

1

Je ne suis pas sûr que c'est la « meilleure pratique », mais je suggère l'approche suivante (sans utiliser les propriétés de haricots -> devrait travailler plus vite).

Généralement, vous savez quel type d'objet vous souhaitez récupérer. Vous pouvez donc fournir un mappeur de ligne correspondant lors de l'exécution du SQL.

Déclarez RowMapper générique coutume abstraite et créer votre propre ligne mappeur pour chaque type de personne, à savoir:

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

par un autre approche que vous pouvez déclarer méthode abstraite dans le mappeur de base pour les accessoires spécifiques, à savoir

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