Как определять и запрашивать связи "один к одному"

Отношение "один к одному" между двумя объектами означает, что каждому экземпляру родительского объекта соответствует ровно один экземпляр дочернего объекта, и наоборот.

Например, в приложении для потоковой передачи музыки у пользователя может быть собственная библиотека песен. У каждого пользователя только одна библиотека, и каждая библиотека принадлежит только одному пользователю. Таким образом, между объектом User и объектом Library существует связь "один к одному".

Чтобы определить и запросить отношения "один к одному" в базе данных, выполните следующие действия:

  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
)

Как запрашивать объекты

Чтобы запросить список пользователей и соответствующих библиотек, сначала необходимо смоделировать связь "один к одному" между двумя объектами.

Чтобы смоделировать связь, создайте новый класс данных, в котором каждый экземпляр будет содержать экземпляр родительского объекта и соответствующий дочерний объект. Добавьте аннотацию @Relation к дочернему объекту. Задайте для параметра parentColumns название столбца первичного ключа родительского объекта, а для параметра entityColumns – название столбца дочернего объекта, который ссылается на первичный ключ родительского объекта.

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

Наконец, добавьте в класс объекта доступа к данным (DAO) функцию, которая возвращает все экземпляры класса данных, связывающего родительский объект с дочерним. Добавьте аннотацию @Transaction, чтобы Room выполнял всю операцию атомарно, поскольку для этой функции требуется, чтобы Room выполнял два запроса.

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

Составные ключи

Если вы определяете связь с помощью составных ключей, укажите несколько столбцов в тегах parentColumns и entityColumns. Порядок столбцов в 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
)