← Назад к вопросам

Что такое аннотация Embedded в Room?

2.0 Middle🔥 152 комментариев
#Android компоненты#Работа с данными

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Аннотация @Embedded в Room

@Embedded — это аннотация в библиотеке Room Persistence Library, которая позволяет внедрять (embed) составной объект (состоящий из нескольких полей) как отдельные колонки в таблицу сущности, вместо создания для него отдельной таблицы и установления связей через внешние ключи. Это мощный инструмент для денормализации данных в локальной базе данных, который упрощает запросы и повышает производительность за счёт сокращения JOIN-операций.

Основное назначение и принцип работы

Когда вы объявляете поле в @Entity-классе с аннотацией @Embedded, Room "разворачивает" все колонки из этого вложенного объекта в таблицу родительской сущности. Например, если у вас есть объект Address с полями street, city и postalCode, и вы встраиваете его в сущность User, то в таблице users появятся колонки: street, city, postalCode (или с префиксом, если используется prefix).

Пример базового использования

// Вложенный объект (не является отдельной Entity)
data class Address(
    val street: String?,
    val city: String?,
    val postalCode: String
)

// Основная сущность
@Entity(tableName = "users")
data class User(
    @PrimaryKey
    val id: Long,
    val name: String,

    @Embedded // Аннотация указывает Room "развернуть" поля Address в таблицу users
    val address: Address?
)

После компиляции Room сгенерирует таблицу users со следующими колонками: id, name, street, city, postalCode. При запросе SELECT * FROM users вы получите полностью собранный объект User с вложенным Address.

Ключевые особенности и параметры

  1. Отсутствие необходимости в отдельной таблице: Объект, помеченный @Embedded, не должен быть аннотирован @Entity. Это простая data class или POJO. Room не создаёт для него отдельную таблицу, что отличает @Embedded от отношений @Relation или foreignKey.

  2. Параметр prefix:

    Полезен, когда нужно встроить несколько объектов одного типа или когда имена колонок могут конфликтовать. Room добавит заданный префикс ко всем колонкам вложенного объекта.

```kotlin
@Entity
data class Company(
    @PrimaryKey
    val id: Long,
    val name: String,

    @Embedded
    val headquarters: Address,

    @Embedded(prefix = "shipping_") // Все колонки Address получат префикс
    val shippingAddress: Address?
)
```
    В таблице появятся колонки: `street`, `city`, `postalCode` (для headquarters) и `shipping_street`, `shipping_city`, `shipping_postalCode`.

  1. Работа с Nullability: Если само встроенное поле (address) равно null, то все его колонки в таблице будут NULL. При загрузке, если все колонки вложенного объекта null, то поле будет равно null.

Практическое применение и преимущества

  • Упрощение запросов: Не требуется выполнять JOIN для получения связанных данных. Все данные извлекаются одним запросом из одной таблицы.

  • Повышение производительности: Операции чтения становятся быстрее, так как избегаются дорогостоящие соединения таблиц. Это особенно важно на мобильных устройствах с ограниченными ресурсами.

  • Моделирование сложных структур: Идеально подходит для объектов-значений (Value Objects) в контексте Domain-Driven Design, таких как координаты (LatLng), денежные суммы (Money) или, как в примере, адреса.

  • Использование в DAO: Аннотацию @Embedded можно использовать не только в сущностях, но и в классах-результатах запросов (POJO для @Query), чтобы объединять данные из нескольких таблиц в одном объекте для ответа.

    data class UserWithDepartment(
        @Embedded
        val user: User,
    
        @Embedded
        val department: Department // Department - это тоже @Entity
    )
    
    @Dao
    interface UserDao {
        @Query("SELECT * FROM user, department WHERE user.departmentId = department.id")
        fun getUsersWithDepartments(): List<UserWithDepartment>
    }
    

Ограничения и отличия от других аннотаций

  • Не для коллекций: @Embedded предназначено для одиночных объектов. Для встраивания списков объектов используйте @Relation.
  • Отличие от @Relation: @Relation решает обратную задачу — она загружает связанные сущности отдельным запросом (или через JOIN с последующим маппингом) и предполагает наличие отдельной таблицы и связи между ними. @Embedded денормализует данные, храня их в одной таблице.
  • Повторение данных: Основной недостаток — возможная избыточность данных. Если один и тот же адрес используется для многих пользователей, при денормализации он будет дублироваться в каждой строке, что может привести к аномалиям обновления. В таких случаях больше подходит классическая нормализованная схема с отдельной таблицей addresses и связью через foreignKey.

Заключение

Аннотация @Embedded — это эффективный инструмент Room для оптимизации структуры базы данных под конкретные сценарии чтения. Она позволяет проектировать объектную модель, максимально удобную для бизнес-логики приложения, минимизируя при этом сложность запросов и повышая скорость их выполнения. Решение о её использовании должно приниматься на основе анализа частоты операций чтения/записи и требований к целостности данных в вашем приложении.

Что такое аннотация Embedded в Room? | PrepBro