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

2 つのエンティティ間の 1 対 1 のリレーションとは、親エンティティの各インスタンスが子エンティティの 1 つのインスタンスに対応するリレーション、あるいはその逆のリレーションです。

たとえば、音楽ストリーミング アプリで、ユーザーが自分の所有する曲のライブラリを持っている場合を考えてみましょう。各ユーザーはライブラリを 1 つだけ持ち、各ライブラリは 1 人のユーザーに対応しています。したがって、User エンティティと Library エンティティの間には 1 対 1 のリレーションがあります。

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

  1. **リレーションを定義する**: 両方のエンティティのクラスを作成し、 一方のエンティティが他方のエンティティの主キーを参照するようにします。
  2. エンティティのクエリを実行する: 新しいデータクラスでリレーションをモデル化し、 関連データを取得する関数を作成します。

リレーションを定義する

1 対 1 のリレーションを定義するには、まず 2 つのエンティティにそれぞれクラスを作成します。一方のエンティティには、他方のエンティティの主キーを参照する変数を含める必要があります。

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

@Entity
data class Library(
    @PrimaryKey val libraryId: Long,
    val userOwnerId: Long
)

エンティティのクエリを実行する

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

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

data class UserAndLibrary(
    @Embedded val user: User,
    @Relation(
        parentColumns = ["userId"],
        entityColumns = ["userOwnerId"]
    )
    val library: Library
)

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

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

複合キー

複合キーを使用してリレーションを定義する場合は、parentColumnsentityColumns に複数の列を指定します。parentColumns の列の順序は、entityColumns の列の順序と一致する必要があります。

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

@Entity
data class Library(
    @PrimaryKey val libraryId: Long,
    val userFirstName: String,
    val userLastName: String
)

data class UserAndLibrary(
    @Embedded val user: User,
    @Relation(
        parentColumns = ["firstName", "lastName"],
        entityColumns = ["userFirstName", "userLastName"]
    )
    val library: Library
)