В чем разница между аннотациями @ForeignKey и @Relation в базе данных Room? - PullRequest
0 голосов
/ 23 октября 2019

Я не могу понять разницу между этими аннотациями. В моем случае я хочу создать отношение «один ко многим» между таблицами. И нашел два варианта: один с @ForeignKey и другой с @ Relation

Также я обнаружил, что если я обновлю строку (например, с помощью OnCoflictStrategy.Replace), я потеряю внешний ключ для этой строки, верно ли это?

1 Ответ

0 голосов
/ 23 октября 2019

A @ ForeignKey определяет ограничение (так называемое правило), которое требует, чтобы дочерние столбцы существовали в родительских столбцах. Если предпринята попытка нарушить это правило, возникает конфликт (который может быть обработан различными способами с помощью определения onDelete / onUpdate).

@ Relationship используется для определения отношения, гденесколько дочерних объектов (возможно, дочерних объектов внешнего ключа) возвращаются в родительский объект.

Под всем этим @ Relation автоматически (эффективно) объединяет таблицы и генерирует количество дочерних объектов. Хотя @ ForeignKey влияет только на схему (за исключением обработки onDelete / onUpdate), это не приводит к объединению соответствующих таблиц.

Возможно, рассмотрим следующее: -

Служебный объект

@Entity(
    tableName = "services"
)
class Services {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "services_id")
    var id: Long = 0
    var service_date: String = ""
    var user_mobile_no: String = ""

}

и

Служебный объект : -

@Entity(
    tableName = "service_detail",
    foreignKeys = [
        ForeignKey(
            entity = Services::class,
            parentColumns = ["services_id"],
            childColumns = ["services_id"],onDelete = ForeignKey.SET_DEFAULT
        )
    ]
)
class ServiceDetail {

    @PrimaryKey
    var id: Long? = null;
    var services_id: Long = 0;
    @ColumnInfo(defaultValue = "1")
    var service_type_id: Long = 0;

    constructor()

    @Ignore
    constructor(services_id: Long, service_type_id: Long) {
        this.services_id = services_id
        this.service_type_id = service_type_id
    }
}
  • Это говорит о том, что для добавления ServiceDetail значение столбца services_id ДОЛЖНО быть значением, которое существует в столбце services_id таблицы services , в противном случае возникнет конфликт. Кроме того, если строка удаляется из таблицы служб, то все строки в таблице service_detail, которые ссылаются на эту строку, также будут удалены (в противном случае строка не может быть удалена из таблицы служб).

Теперь рассмотрим этот нормальный класс (POJO), который НЕ является сущностью (она же таблица): -

class ServiceWithDetail {

    @Embedded
    var services: Services? = null

    @Relation(entity = ServiceDetail::class,parentColumn = "services_id",entityColumn = "services_id")
    var serviceDetail: List<ServiceDetail>? = null
}

Это грубо говоря, когда вы запрашиваете объект ServiceWithDetail, затем получаете объект services вместе со спискомсвязанные объекты service_detail

У вас будет Дао, например: -

@Query("SELECT * FROM services")
fun getAllServices() :List<ServiceWithDetail>

Таким образом, он получит все услуги из таблицы служб вместе с соответствующими (т. е. где services_id вservices_detail совпадает с services_id текущей обрабатываемой строки служб).

onConflictStrategy

REPLACE выполняет следующие действия: -

Когда происходит нарушение ограничения UNIQUE или PRIMARY KEY, алгоритм REPLACE удаляет ранее существующие строки, вызывающие ограничениенарушение до вставки или обновления текущей строки, и команда продолжает выполняться нормально.

Если происходит нарушение ограничения NOT NULL, разрешение конфликта REPLACE заменяет значение NULL значением по умолчанию для этого столбца или, если столбецне имеет значения по умолчанию, тогда используется алгоритм ABORT. Если возникает ограничение CHECK или нарушение внешнего ключа, алгоритм разрешения конфликтов REPLACE работает как ABORT.

Когда стратегия разрешения конфликтов REPLACE удаляет строки для удовлетворения ограничения, триггеры delete срабатывают тогда и только тогда, когда рекурсивные триггеры

Хук обновления не вызывается для строк, которые удаляются стратегией разрешения конфликтов REPLACE. REPLACE также не увеличивает счетчик изменений. Исключительное поведение, определенное в этом параграфе, может измениться в будущем выпуске. REPLACE

Отсюда и потенциальное поведение, которое вы испытали. Однако это зависит от того, что делает обновление. Если значения для ForeignKey (s) отличаются, тогда они должны, предполагая, что нет никакого конфликта Внешнего ключа, замените значение внешнего ключа новым допустимым значением. Если значение (я) внешнего ключа не изменено, то строка замены будет иметь те же внешние ключи.

...