2009-12-02 11 views
5

Volevo sapere quali considerazioni la community considera le "migliori pratiche" rispetto alla mappatura delle gerarchie di classi con Spring JDBC.Spring JDBC RowMapper con classe Hiearchies

Non abbiamo la possibilità di utilizzare uno strumento ORM completo, tuttavia stiamo utilizzando il JDBC Spring per alleviare parte della noiosa natura di JDBC. Una classe che sfruttiamo molto regolarmente è BeanPropertyRowMapper per la sua facilità d'uso e la possibilità di avere accesso alla proprietà del bean insensibile al tipo dal nostro set di risultati.

Ho una gerarchia di classi che riconduce tutte a una singola tabella (prendendo l'approccio table-per-hiearchy per questa piccola gerarchia di classi). In quanto tale, la tabella contiene una colonna classId che può essere utilizzata per determinare quale classe dovrebbe essere istanziata. Ex. 1 = Manager, 2 = Impiegato, 3 = Appaltatore. Tutti questi sono "Persone" ma ogni sottoclasse di persone ha alcuni attributi che sono unici per la loro classe.

Il mio primo pensiero è quello di creare una sottoclasse di BeanPropertyRowMapper e provare a iniettare questa logica per dire "se la colonna A = 1 crea un'istanza di Manager e quindi esegui l'associazione nomral".

Questo sembra un approccio ragionevole? Ci sono altri suggerimenti che potrebbero aver funzionato per te?

Grazie in anticipo per le vostre risposte,

Justin N.

risposta

4

Non sembra che ci sia un posto nella sottoclasse in cui si potrebbe aggiungere un gancio per cambiare la classe senza copiare completamente l'attuazione di mapRow() per BeanPropertyRowMapper. Il tuo approccio migliore potrebbe essere quello di creare una classe RowMapper che delega al BeanPropertyRowMapper appropriato.

Ad esempio:

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

Grazie per la risposta. Questo è quello che ho finito per fare! Buono per ottenere qualche convalida. – jnt30

1

Io non sono sicuro che sia la 'best practice', ma vi suggerisco il seguente approccio (senza l'utilizzo di proprietà del bean -> dovrebbe funzionare più velocemente).

Di solito sai che tipo di oggetto ti aspetti di recuperare. Quindi puoi fornire il corrispondente compilatore di riga quando esegui sql.

Dichiarare astratto personalizzato RowMapper generica e creare proprio mapper riga per ogni tipo di persona, vale a dire:

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

Con altro approccio è possibile dichiarare il metodo astratto in mapper base per puntelli specifici, vale a dire

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