1 対多のリレーションを定義してクエリを実行する

2 つのエンティティ間の 1 対多のリレーションとは、親エンティティの各インスタンスが子エンティティの 0 個以上のインスタンスに対応し、子エンティティの各インスタンスは親エンティティの 1 つのインスタンスにだけ対応するリレーションです。

音楽ストリーミング アプリで、ユーザーがプレイリストに曲を整理できる機能があるとします。各ユーザーが作成できるプレイリストの数に制限はありませんが、各プレイリストの作成者は 1 人だけです。したがって、User エンティティと Playlist エンティティの間には 1 対多のリレーションがあります。

データベースで 1 対多のリレーションシップを定義してクエリを実行する手順は次のとおりです。

  1. リレーションを定義する: 両方のエンティティのクラスを作成します。子エンティティは親の主キーを参照します。
  2. エンティティをクエリする: 新しいデータクラスでリレーションシップをモデル化し、関連データを取得する関数を実装します。

リレーションシップを定義する

1 対多のリレーションを定義するには、まず各エンティティのクラスを作成します。1 対 1 のリレーションと同様に、子エンティティには、親エンティティの主キーを参照する変数を含める必要があります。

@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
)

エンティティをクエリする

ユーザーと対応するプレイリストのリストをクエリするには、最初に 2 つのエンティティ間の 1 対多のリレーションをモデル化する必要があります。

関係をモデル化するには、新しいデータクラスを作成します。このクラスの各インスタンスは、親エンティティのインスタンスと、対応するすべての子エンティティのインスタンスのリストを保持します。子エンティティのリストを表すプロパティに @Relation アノテーションを追加します。parentColumns を親エンティティの主キー列の名前に設定し、entityColumns を親エンティティの主キーを参照する子エンティティの列の名前に設定します。

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

最後に、親エンティティと子エンティティをペアにするデータクラスのすべてのインスタンスを返す関数をデータアクセス オブジェクト(DAO)クラスに追加します。@Transaction アノテーションを追加して、Room が操作全体をアトミックに実行するようにします。このアノテーションは、関数で Room に 2 つのクエリを実行させる必要があるため必要です。

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

複合キー

複合キーを使用してリレーションシップを定義する場合は、parentColumnsentityColumns で複数の列を指定します。parentColumns の列の順序は、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>
)