2015-06-01 12 views
14

Fondamentalmente è stata fatta la stessa domanda circa un anno fa per slick 2.x (scala slick one-to-many collections). Mi chiedo se non sia stato fatto alcun progresso con il rilascio di chiazze reattive.Slick 3.0.0: come eseguire query relazioni uno-a-molti/molti-a-molti

Diciamo per esempio che abbiamo tre tabelle. library, book e library_to_book dove una biblioteca ha molti libri. Quello che voglio è un elenco di biblioteche con i loro libri. In scala questo sarebbe qualcosa come Seq[(Library, Seq[Book])]. La query che ho è il seguente:

val q = (for { 
    l <- libraries 
    ltb <- libraryToBooks if l.id === ltb.libraryId 
    b <- books if ltb.bookId === b.id 
} yield (l, b) 
db.run(q.result).map(result => ???) 

results in questo caso è di tipo Seq[(Library, Book)]. Come devo modificare la mia query per ottenere invece un risultato di tipo Seq[(Library, Seq[Book])]? Qual è il "modo lucido" di scrivere tali query?

risposta

7

IMO il tuo codice sembra buono. Dipende davvero da cosa ti sembra più leggibile. In alternativa, è possibile utilizzare join così:

val findBooksQuery = libraries 
    .join(libraryToBooks).on(_.id === _.libraryId) 
    .join(books).on(_.id === _._2.bookId) 
    .result 

val action = (for { 
    booksResult <- findBooksQuery 
} yield { 
    booksResult.map { row => 
    val (libraryTableRow, libraryToBooksTableRow) = row._1 
    val booksTableRow = row._2 
    // TODO: Access all data from the rows and construct desired DS 
    } 
} 

db.run(action) 

si può quindi fare un groupBy su una particolare chiave per ottenere il tipo di struttura dati che stai cercando. In questo caso, sarebbe più evoluto in quanto si unisce su tre tabelle. Esempio, aggiungi alla tua domanda:

val findBooksQuery = libraries 
    .join(libraryToBooks).on(_.id === _.libraryId) 
    .join(books).on(_.id === _._2.bookId) 
    // To group by libraries.id 
    .groupBy(_._1.id) 
    .result 
+0

Come Sky ha menzionato in precedenza in un commento, non c'è modo di farlo in una bella atmosfera. Immagino che il metodo '.groupBy' che hai proposto sia la strada da percorrere per ora. – Roman

+0

@Roman Questo restituisce un 'Seq' vuoto se una libreria non ha libri? Se è così, potrebbe non essere all'altezza delle aspettative. – acjay

+0

@acjay: In questo caso ciò porta a un 'Seq' vuoto in effetti. Se vuoi avere tutte le librerie nel tuo risultato, non importa se hanno libri o no, puoi usare outer join invece di inner join ('joinLeft',' joinRight' in termini slick). Sentiti libero di aprire una domanda successiva se questo non è quello che stai cercando :) – Roman

0

A ciò che si desidera mappare, db.run restituisce un futuro (di qualcosa), un futuro [Seq [(Libreria, Seq [Libro])]] nel tuo caso. Quando mappi su un futuro, hai accesso al Seq e puoi trasformarlo in qualcos'altro per ottenere un nuovo Futuro.

+0

Grazie per la risposta. Purtroppo questo non è quello che stavo cercando. Ho appena aggiornato la mia domanda e ho cercato di essere un po 'più specifica. – Roman

+2

@Roman Al momento, non c'è modo di farlo in Slick. – Sky

Problemi correlati