Что такое primary key и foreign key и для чего они нужны
Что проверяют
Базовую реляционную грамотность и то, переносите ли вы её на локальную базу приложения. В мобильной разработке это SQLite через Room, где часть привычных гарантий выключена по умолчанию, и знание этих нюансов отличает практика от выучившего определение.
Как отвечать
Первичный ключ это столбец или набор столбцов, однозначно определяющий строку: уникален, не пуст, стабилен во времени. Внешний ключ это столбец, значения которого обязаны существовать в ключе другой таблицы; он же задаёт поведение при изменении родителя через каскад, обнуление или запрет.
@Entity(
tableName = "orders",
foreignKeys = [ForeignKey(
entity = UserEntity::class,
parentColumns = ["id"],
childColumns = ["user_id"],
onDelete = ForeignKey.CASCADE
)],
indices = [Index("user_id")]
)
data class OrderEntity(@PrimaryKey val id: String, val userId: String)Про выбор ключа: суррогатный против естественного. Приложению, которое работает офлайн, удобен идентификатор, сгенерированный на клиенте: строку можно создать без сети, а серверный номер хранить отдельным столбцом и заполнять при синхронизации.
Где спотыкаются
Берут в ключ естественное значение вроде почты или телефона. Оно меняется, и правка тянет за собой все ссылающиеся строки. Уникальность такого поля лучше выражать отдельным ограничением, а ключ оставить суррогатным.
Полагают, что база проверит связи сама. В SQLite контроль внешних ключей включается настройкой соединения, и код, работающий мимо Room, легко оставляет её выключенной. Индекс по столбцу внешнего ключа тоже не появляется сам: без него удаление родителя и соединение таблиц читают дочернюю целиком, и Room предупреждает об этом на сборке.
Смешивают первичный ключ, автоинкремент и индекс. Ключ бывает составным, автоинкремент лишь способ выдавать значения, а в SQLite столбец с первичным ключом по историческим причинам допускает пустое значение, если явный запрет не объявлен. Во внешнем ключе пусто допустимо и означает отсутствие связи.