Lavorando con Liferay ed il Service Builder vi sarà sicuramente capitato di dover gestire delle relazioni N-N; come sappiamo, all'interno del file service.xml, è possibile utilizzare l'attributo mapping-table per definire la relazione N-N demandando al Service Builder tutto il lavoro sporco.
Ciò significa che il codice generato dal Service Builder conterrà tutti i metodi per leggere e scrivere record nella tabella di join; non c'è nulla di magico in questo, semplicemente vengono utilizzate determinate classi che si occupano di tutto quanto.
Tuttavia potrebbe capitarvi di dover gestire una relazione N-N a mano, senza poter usare l'attributo mapping-table e quindi potenzialmente perdendo tutti gli automatismi. Per fortuna non è così, se sai cosa fare; esiste infatti l'interfaccia TableMapper che possiamo utilizzare direttamente senza problemi.
Supponiamo di dover gestire la relazione N-N tra autori e libri; all'interno del service.xml avremo pertanto definito 3 entità:
Author, con chiave primaria authorId; Book, con chiave primaria bookId; Author_Book, con chiave primaria composta da authorId e bookId.
Ovviamente il Service Builder ci mette già a disposizione tutti i metodi di base ma quello che vogliamo è avere un metodo che ci restituisca l'elenco degli autori a partire dal libro e l'elenco dei libri a partire dall'autore; infatti sebbene si possano definire dei finder all'interno dell'entità Author_Book (findByAuthorId e findByBookId), questi restituiranno comunque una lista di oggetti Author_Book e non una lista di Author o di Book.
Vediamo quindi come il TableMapper possa aiutarci; apriamo quindi la classe AuthorLocalServiceImpl e definiamo il seguente metodo:
public List<Autor> getBookAuthors(long bookId, int start, int end, OrderByComparator comparator)
throws SystemException {
TableMapper tableMapper = TableMapperFactory.getTableMapper(
Author_BookImpl.TABLE_NAME,
"authorId", "bookId",
authorPersistence, bookPersistence);
return tableMapper.getLeftBaseModels(bookId, start, end, comparator);
} Come vedete è veramente semplicissimo; prima di tutto si ottiene un'istanza del TableMapper attraverso la factory. I parametri della factory sono i seguenti:
- Nome della tabella di join (abbiamo già una bella costante);
- Nome della chiave primaria della tabella di sinistra della relazione N-N;
- Nome della chiave primaria della tabella di destra della relazione N-N;
- Classe di persistenza della tabella di sinistra della relazione N-N;
- Classe di persistenza della tabella di destra della relazione N-N.
A questo punto possiamo semplicemente invocare uno dei tanti metodi forniti da TableMapper, per leggere o scrivere dati:
getLeftBaseModels, restituisce l'elenco delle entità di sinistra associate allo specifico elemento di destra (ossia l'elenco degli autori in base al libro); getRightBaseModels, restituisce l'elenco delle entità di destra associate allo specifico elemento di sinistra (ossia l'elenco dei libri in base all'autore); addTableMapping, aggiunge un elemento alla relazione N-N; deleteTableMapping, rimuove un elemento dalla relazione N-N; - ...
Chiaramente farete poi una cosa analoga nella classe BookLocalServiceImpl, ma ve lo lascio come esercizio.
Ok, ditemi se non è una figata!