Перейти к основному содержанию
`Ctrl`+`K`

# Контроллер таблицы

Контроллер таблицы (`Api`) служит для транзакционной работы со строками базы данных.

`Api`-контроллер предоставляет:

- кэш строк:

  - один объект `Entity` — одна строка;

  - повторный `load(id)` вернёт тот же экземпляр;

- список изменений — изменения накапливаются до момента `flush()`;

- `flush()` — все изменения (`inserted / updated / deleted`) собираются в `GsSession.flush()` и пишутся пачками;

- счётчик идентификаторов — `insert()` получает уникальный `id` из счётчика.

Для создания контроллера:

1. Создайте базу данных.

2. Создайте сущность.

3. Создайте `Dao`.

4. Создайте `Api`-контроллер.

5. Скомпилируйте проект.
   При компиляции проекта произойдёт генерация необходимых классов.

## Сущность

Сущность описывает таблицу базы данных в терминах ORM.
Для сущности генерируется `Dao`, а также создаётся таблица в базе данных.

Для создания сущности:

1. Создайте `data class`.

2. Унаследуйте класс от `BaseEntity`.

   Совет

   Не создавайте поле `id`, так как оно определено в `BaseEntity`.

3. Добавьте аннотацию `@Entity`.

4. Укажите в аннотации имя таблицы базы данных.

   Внимание

   Имя таблицы должно соответствовать имени класса.

5. Добавьте класс в список `entities` базы данных.

   Пример:

       @Database(
           entities = [SystemEntity::class, User::class]
       )
       abstract class AppDatabase : RoomDatabase()

Пример сущности:

    // db/User.kt
    @Entity(tableName = "User")
    data class User(
        var sName: String? = null,
        var nAge : Int?    = null
    ) : BaseEntity() {
        override fun copyEntity() = copy()
    }

## Dao

`Dao` содержит набор сгенерированных на основе сущности методов для реализации ORM.

1. Создайте абстрактный класс.

2. Унаследуйте его от `BaseDao`.
   В качестве типа укажите сущность для этого `Dao`.

3. Аннотируйте класс аннотацией `@Dao`.

4. Добавьте переменную с `Dao` в класс базы данных.

   Пример:

       abstract class AppDatabase : RoomDatabase() {
           abstract val userDao: UserDao
       }

Пример `Dao`:

    // db/UserDao.kt
    @Dao
    abstract class UserDao : BaseDao<User>()

## Создание Api

1. Создайте класс.
   Класс должен принимать параметр `ctx: ApiBeanContext`. Контекст нужен для работы механизма инъекции зависимостей.

2. Унаследуйте класс от `DbBaseApiGen`.
   `DbBaseApiGen` автоматически подставляет `dbRoom` и `dbSession` через DI-процессор.

    @GsApiBean
    class UserApi(ctx: ApiBeanContext)
        : DbBaseApiGen<User, UserDao, AppDatabase>(ctx) {

        override val dao get() = dbRoom.userDao
        override fun newEntity() = User()

        fun seedDemo() {
            // инициализация демо-данных
        }
    }

## Создание Api на основе рефлексии

1. Создайте класс.

2. Унаследуйте класс от `DbBaseApi`.

Внимание

Раздел находится в разработке.

## Оптимизация производительности

- Делайте `insertAll(list)` через `Api` — это всегда batch без `forEach`.

- Используйте `rowCache` для реконфигурируемых фильтров:
  запросили 500 `id`, фильтруете в Kotlin-коде, не дёргая SQL повторно.