首页 > 解决方案 > Room 数据库中的@ForeignKey 和@Relation 注释有什么区别?

问题描述

我无法理解这些注释之间的区别。在我的用例中,我想在表之间创建一对多的关系。并找到了两种选择:一种使用@ForeignKey,另一种使用@Relation

我还发现,如果我更新该行(例如使用 OnCoflictStrategy.Replace),我将丢失该行的外键,这是真的吗?

标签: androidandroid-roomandroid-architecture-components

解决方案


@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 = ""

}

ServiceDetail 实体:-

@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表的services_id列中的值,否则会发生冲突。此外,如果从 services 表中删除了一行,则 service_detail 表中引用该行的任何行也将被删除(否则该行无法从 services 表中删除)。

现在考虑这个普通类(POJO),它不是一个实体(又名表):-

class ServiceWithDetail {

    @Embedded
    var services: Services? = null

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

这大致是说当您请求 ServiceWithDetail 对象然后获取服务对象以及相关 service_detail 对象的列表时

你会有一个道,比如:-

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

因此,它将从服务表中获取所有服务以及相关服务(即 services_detail 中的 services_id 与正在处理的当前服务行的 services_id 相同)。

冲突策略

REPLACE执行以下操作:-

当 UNIQUE 或 PRIMARY KEY 约束违规发生时,REPLACE 算法会在插入或更新当前行之前删除导致约束违规的预先存在的行,并且命令会继续正常执行。

如果发生 NOT NULL 约束冲突,则 REPLACE 冲突解决方案将 NULL 值替换为该列的默认值,或者如果该列没有默认值,则使用 ABORT 算法。如果发生 CHECK 约束或外键约束冲突,则 REPLACE 冲突解决算法的工作方式与 ABORT 类似。

当 REPLACE 冲突解决策略删除行以满足约束时,当且仅当启用递归触发器时,删除触发器才会触发。

对于由 REPLACE 冲突解决策略删除的行,不会调用更新挂钩。REPLACE 也不会增加更改计数器。本段中定义的异常行为可能会在未来的版本中发生变化。代替

因此,您所经历的行为的可能性。但是,这取决于更新在做什么。如果 ForeignKey(s) 的值不同,那么他们应该假设没有外键冲突,用新的有效值替换外键值。如果外键值不变,则替换行将具有相同的外键。


推荐阅读