Как сделать автоинкремент первичного ключа в Room (Kotlin)?
Решение: используйте `@PrimaryKey(autoGenerate = true)`
В Room для автоинкремента первичного ключа нужно добавить параметр autoGenerate = true в аннотацию @PrimaryKey. При этом тип поля должен быть целочисленным (Int или Long) и не nullable. Room сам позаботится о генерации значения при вставке.
Вот правильная реализация вашей сущности:
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0, // Значение по умолчанию не важно, Room перезапишет его
val name: String,
val age: Int
)
Теперь при вставке объекта User вы можете не указывать id:
val newUser = User(name = "Иван", age = 25)
val insertedId = userDao.insert(newUser) // Room вернёт сгенерированный id
Важные моменты:
- Тип поля:
IntилиLong. Room автоматически преобразует их в INTEGER в SQLite. - Значение по умолчанию: Можно указать любое (0, -1, null — если использовать nullable тип, но лучше не надо). Room всё равно заменит его сгенерированным значением.
- Nullable не нужен: В отличие от некоторых ORM, Room позволяет использовать non-null поля с
autoGenerate = true. Просто задайте значение по умолчанию (например, 0).
Что происходит под капотом?
Когда вы указываете autoGenerate = true, Room создаёт SQLite таблицу с INTEGER PRIMARY KEY AUTOINCREMENT. Это гарантирует, что каждый новый id будет больше предыдущего (даже после удаления записей). Если вам не нужна такая гарантия, можно опустить autoGenerate — Room всё равно будет использовать INTEGER PRIMARY KEY, что тоже даёт автоинкремент, но может повторно использовать id удалённых записей.
Полный пример DAO и вызова:
@Dao
interface UserDao {
@Insert
suspend fun insert(user: User): Long // Возвращает сгенерированный id
@Query("SELECT * FROM users")
suspend fun getAllUsers(): List<User>
}
// В репозитории или ViewModel:
val user = User(name = "Анна", age = 30)
val id = userDao.insert(user)
Log.d("Room", "Новый пользователь с id = $id")
Если вы используете @Insert без возвращаемого значения, ничего страшного — id всё равно будет сгенерирован и сохранён в объекте User. Но чтобы получить его сразу, лучше возвращать Long.
Надеюсь, это поможет! Если остались вопросы — пишите в комментариях.
<<Альтернативный подход: использование Long и автоинкремент без autoGenerate
Если вам не нужна строгая гарантия возрастания id (например, при удалении записи id может быть переиспользован), можно вообще не указывать autoGenerate = true. Room по умолчанию использует INTEGER PRIMARY KEY в SQLite, что уже даёт автоинкремент:
@Entity(tableName = "users")
data class User(
@PrimaryKey
val id: Long = 0, // Long вместо Int — более надёжно для больших таблиц
val name: String,
val age: Int
)
В этом случае Room сам назначит id при вставке, но если вы удалите запись с id=5, следующая вставка может получить id=5 (а не 6, как с AUTOINCREMENT). Это экономит место в базе и ускоряет запись.
Для большинства приложений (список задач, контакты, заметки) такой подход абсолютно нормален. Выбирайте autoGenerate = true только если критично, чтобы id всегда увеличивались (например, для синхронизации с сервером).
Ответов пока нет.
Войдите чтобы оставить ответ