2013-03-19 13 views
14

Sto usando Spring JDBC e sono un po 'insicuro su come lavorare con più relazioni uno-a-molti (o molti-a-molti). In questo caso sto iniettando un repository in uno dei miei risultati in modo tale da poter recuperare le sue associazioni. È questo il modo di farlo? È male? Ci sono altri modi migliori?Molteplici relazioni uno-a-molti in Spring JDBC

Nota: ho lasciato fuori l'iniezione di repository

public class SomeResultSetExtractor implements ResultSetExtractor { 

    public Object extractData(ResultSet rs) throws SQLException, DataAccessException { 
    List result = new LinkedList(); 

    while (rs.next()) { 
     SomeObject object = new SomeObject(rs.getString(1), rs.getLong(2)); 
     result.add(object); 

     List<AnotherObject> otherObjects = anotherRepository.findAllById(object.getId); 
     object.setOtherObjects(otherObjects); 
     // and so on 
    } 

    return result; 

    } 
} 

Okey quindi dopo aver letto Dmytro Polivenok risposta che ho cambiato all'interfaccia RowMapper invece e attualmente sto utilizzando gli altri repository per popolare tutte le associazioni come Mostro nel mio esempio È un buon modo per farlo?

+0

Il repository avvia una nuova query SQL? – tkr

risposta

4

Penso che una buona pratica per Spring JDBC e query SQL in generale sia quella di utilizzare una query per ogni entità.

E.g. assumere questo modello:

  • clienti (customerId, nome, età, ...)
  • Indirizzo (customerId, tipo, via, città, ...)
  • PaymentOption (customerId, numero di carta, cardType , ...)

  • Cliente 1 --- * Indirizzo

  • Cliente 1 --- * PaymentOption

Vorrei costruire 3 interrogazioni, 3 Tao 3 ResultSetExtractors/RowcallbackHandlers:

  • CustomerDao con readCustomerData (Cliente o List)
  • AddressDao con readAddressForCustomer (Cliente o List)
  • PaymentOptionDao con readPaymentOptionsForCustomer (Cliente o List

Se si esegue questa operazione in 1 query, è necessario creare una logica per ripristinare il prodotto cartasiano.

  • I.e. se il cliente ha 3 indirizzi e 2 opzioni di pagamento, la query restituirà 6 righe.
  • Questo diventa piuttosto difficile, se Indirizzo o PaymentOption non ha una propria chiave primaria.

Per molti a molti:

  • cliente * * --recommends-- prodotto

avrei probabilmente costruire:

  • CustomerDao.readRecommendationsAndProductKeys
  • getDistinctListOfProductKeysFromRecommendations
  • ProductDao.readProducts
  • replaceProductKeysByProductsOnRecommendations

come non si potrebbe riutilizzare ProductDao.readProducts per

  • cliente * --buys-- * Prodotto o
  • prodotti Navigazione 1 --- * Prodotto
+0

Grazie, è praticamente lo stesso che ho fatto. – LuckyLuke

+0

Non è inefficiente in quanto stai effettuando diversi round trip nel database? Supponiamo che tu abbia un oggetto che ha 3 collezioni (da una a molte relazioni) Se hai bisogno di tutti i dati, la tua query restituisce 100 oggetti, a tua volta emetterò altre 300 query per ottenere i dati completi, per un totale di 301 query – greyfox

+0

l'idea è di raggruppare ogni query. È possibile chiamare readCustomerData con 100 ID cliente e dividere il risultato in base all'ID cliente. Quindi per i 100 clienti avresti ancora solo 3 richieste. – tkr

4

Penso che il tuo codice funzionerà, ma la preoccupazione qui riguarda l'utilizzo di ResultSetExtractor che è principalmente per la struttura JDBC stessa, e per la maggior parte dei casi documentation consiglia di utilizzare RowMapper.

Quindi un approccio alternativo sarebbe avere un metodo nel DAO che seleziona e mappa l'oggetto padre. Quindi, per ogni oggetto richiamare altro repository o metodo privato che seleziona e associa gli oggetti figlio e quindi collegare gli oggetti figlio ai genitori in base al tipo di relazione (unidirezionale o bidirezionale). Questo approccio può anche consentire di controllare se si desidera caricare oggetti figlio o meno.

Ad esempio, è possibile controllare l'applicazione Primavera PetClinic che ha SimpleJdbcClinic class

Se è possibile utilizzare altri framework, si può considerare mybatis, è più circa la mappatura e consente di controllare il codice SQL.

+0

Ciao, non sono sicuro di aver compreso correttamente la tua risposta. Diciamo che hai le classi: film, attore, genere e commento. Vuoi restituire un oggetto film con tutte le sue associazioni: un film ha molti attori, molti commenti e un genere. Come lo faresti? – LuckyLuke

+0

È possibile avere il metodo getMovies, che eseguirà la selezione per film e genere e li mapperà agli oggetti. Quindi, per ogni film, richiamare il Repository per gli attori con select/map e Repository per i commenti con select/map (o se gli attori e i commenti esistono nel tuo contesto solo in termini di film, puoi farlo con metodi privati). Dopo aver impostato commenti e autori sull'oggetto film –

+0

Okey, quindi se si passa all'interfaccia di rowmapper è meglio. Tuttavia, cosa fai con i casi molti a molti? Qual è il modo migliore per mapparli? Diciamo che ogni film ha molti attori e ogni attore appartiene a molti film. Allora hai una tabella di join? Crei un metodo, ad esempio, nel repository degli attori denominato findAllActorsForMovie che utilizza la tabella di join e la tabella degli attori per creare un risultato? Proprio come faresti in uno-a-molti? – LuckyLuke

Problemi correlati