Definire e eseguire query sulle relazioni one-to-many

Una relazione one-to-many tra due entità è una relazione in cui ogni istanza dell'entità padre corrisponde a zero o più istanze dell'entità figlio, ma ogni istanza dell'entità figlio può corrispondere a una sola istanza dell'entità padre.

Nell'esempio dell'app di streaming musicale, supponiamo che l'utente possa organizzare i brani in playlist. Ogni utente può creare tutte le playlist che vuole, ma ogni playlist viene creata da un solo utente. Esiste quindi una relazione one-to-many tra l'entità User e l'entità Playlist.

Per definire ed eseguire query sulle relazioni one-to-many nel database:

  1. Definisci la relazione: crea classi per entrambe le entità, con l'entità figlio che fa riferimento alla chiave primaria dell'entità padre.
  2. Esegui query sulle entità: modella la relazione in una nuova classe di dati e implementa una funzione per recuperare i dati correlati.

Definisci la relazione

Per definire una relazione one-to-many, crea prima una classe per ogni entità. Come in una relazione one-to-one, l'entità figlio deve includere una variabile che fa riferimento alla chiave primaria dell'entità padre.

@Entity
data class User(
    @PrimaryKey val userId: Long,
    val name: String,
    val age: Int
)

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userCreatorId: Long,
    val playlistName: String
)

Esegui query sulle entità

Per eseguire query sull'elenco degli utenti e sulle playlist corrispondenti, devi prima modellare la relazione one-to-many tra le due entità.

Per modellare la relazione, crea una nuova classe di dati. Ogni istanza di questa classe contiene un'istanza dell'entità padre e un elenco di tutte le istanze dell'entità figlio corrispondenti. Aggiungi l'annotazione @Relation alla proprietà che rappresenta l'elenco delle entità figlio. Imposta parentColumns sul nome della colonna di chiave primaria dell'entità padre e imposta entityColumns sul nome della colonna dell'entità figlio che fa riferimento alla chiave primaria dell'entità padre.

data class UserWithPlaylists(
    @Embedded val user: User,
    @Relation(
        parentColumns = ["userId"],
        entityColumns = ["userCreatorId"]
    )
    val playlists: List<Playlist>
)

Infine, aggiungi una funzione alla classe Data Access Object (DAO) che restituisce tutte le istanze della classe di dati che accoppiano l'entità padre e l'entità figlio. Aggiungi l'annotazione @Transaction in modo che Room esegua l'intera operazione in modo atomico. Questa annotazione è necessaria perché la funzione richiede a Room di eseguire due query.

@Transaction
@Query("SELECT * FROM User")
suspend fun getUsersWithPlaylists(): List<UserWithPlaylists>

Chiavi composite

Se definisci la relazione utilizzando chiavi composite, specifica più colonne in parentColumns e entityColumns. L'ordine delle colonne in parentColumns deve corrispondere all'ordine delle colonne in entityColumns.

@Entity(primaryKeys = ["firstName", "lastName"])
data class User(
    val firstName: String,
    val lastName: String,
    val age: Int
)

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userFirstName: String,
    val userLastName: String,
    val playlistName: String
)

data class UserWithPlaylists(
    @Embedded val user: User,
    @Relation(
        parentColumns = ["firstName", "lastName"],
        entityColumns = ["userFirstName", "userLastName"]
    )
    val playlists: List<Playlist>
)