首页 > 解决方案 > Room @Relation 与复合主键

问题描述

我的问题是这个问题的扩展(也是我的:))->房间复合主键链接到外键 所以,如果我有这个类:

public class FoodWithIngredients extends Food{

    @Relation(parentColumn = "id", entityColumn = "food_id", entity = 
    Ingredient.class)
    private List<Ingredient> mIngredients;

}

但是PrimaryKey“食物”表是composite (primaryKeys = {"id", "language_id"})

如何使@Relation 返回记录在哪里"parentColumn = {"id", "language_id"}, entityColumn = {"food_id", food_language_id}"

标签: androidsqliteandroid-roomcomposite-primary-key

解决方案


注释 @Relation 仍然不提供对复合主键的支持。

获取查询多个表的数据以保持表清洁的最简单方法是使用 @Embedded 注释。如果您不介意变脏,您可以添加一个额外的字段,在其中连接主键的字段,并在该字段上使用 @Relation,这会带来维护字段的所有风险以及对其数据进行潜在错误比较的风险。可能值得,不知道对我来说是个坏主意。

所以干净的解决方案。提供了下一张桌子。

//Multiple Staff and Machine can participate on a WorkOrder and they do hours of work related to it

@Entity
data class Staff(
        @PrimaryKey val jdeNumber: String,
        val idNfc: String,
        val staffDescription: String,
        val triadorNumber: String,
        val approverId: Int)

@Entity(primaryKeys = ["machineId"])
data class Machine(
        val machineId: String,
        val machineNumber: String,
        val machineDescription: String,
        val machineNumberAux: String,
        val manufacturer: String,
        val model: String,
        val productionNumber: String,
        val hasHours: Boolean)

//A WorkOrder may have staff, machine or both
@Entity
data class WorkOrder(
        @PrimaryKey val woId: String,
        val date: Long,
        val comments: String = "",
        val userId: String,
        val partStatus: Int
)

//Embedded annotation creates all the fields from the entity inside these tables and add to the field name a prefix, then when we join tables we have no name conflict
@Entity(
        primaryKeys = ["woIdStaff", "wo_jdeNumber"],
        foreignKeys = [
                ForeignKey(entity = WorkOrder::class,
                        parentColumns = ["woId"],
                        childColumns = ["woIdStaff"],
                        onUpdate = ForeignKey.CASCADE,
                        onDelete = ForeignKey.RESTRICT)]
)
data class WorkOrderStaff(
        val woIdStaff: String,
        @Embedded(prefix = "wo_")
        val staff: Staff,
        val hourFrom: Long,
        val hourTo: Long,
        val hoursUsed: Long
)

@Entity(
        primaryKeys = ["woIdMachine", "wo_machineId"],
        foreignKeys = [
                ForeignKey(entity = WorkOrder::class,
                        parentColumns = ["woId"],
                        childColumns = ["woIdMachine"],
                        onUpdate = ForeignKey.CASCADE,
                        onDelete = ForeignKey.RESTRICT)]
)
data class WorkOrderMachine(
        val woIdMachine: String,
        @Embedded(prefix = "wo_")
        val machine: Machine,
        val hourFromMachine: Long,
        val hourToMachine: Long,
        val hoursUsedMachine: Long
)

//Important this entity is the one that maps from JOIN queries
data class FullWorkOrder(
        @Embedded
        val workOrder: WorkOrder
        @Embedded
        val staff: WorkOrderStaff?
        @Embedded
        val machine: WorkOrderMachine?
)

然后,我们要查询与在其中工作的员工和机器加入的所有 workOrders 以及每个 workOrders 的工作时间。所以我们在我们的 Dao 中写了一个查询。

@Query("select * from WorkOrder LEFT JOIN WorkOrderStaff ON woId = woIdStaff LEFT JOIN WorkOrderMachine ON woId = woIdMachine")
abstract fun getAllFullWorkOrders(): List<FullWorkOrder>

当您测试 SQL 时,到实体 FullWorkOrder 的这种映射的行为类似于表可视化上的 Db 查询,您必须对其进行映射,这样您就不会复制数据行或分配不正确的数据,具体取决于连接的复杂性。我建议将数据移动到键值映射,然后加入所有过滤重复键。在这种情况下,我们将映射到我们在 UI -> DomainWorkOrder 上使用的实体。

data class DomainWorkOrder(
    val id: String,
    .
    .
    .
    val staffList: List<StaffRow>
    val machineList: List<MachineRow>
)

我已经从示例中删除了我正在使用的表的真正复杂性,这就是为什么您在 SQL 上看不到任何复合 LEFT JOIN 的原因。我有 8 个表并入 WorkOrder(1-n),其中 2 个在其中嵌套了 1-n 关系。我保证这在大多数情况下都可以解决问题,如果您尝试将 Staff 表加入实体 FullWorkOrder 以获取最新数据,请小心,我对此有不好的体验。

我知道这不是纯粹的,但架构受到尊重,查询/映射过程不需要大量的工作和维护。希望能帮助到你!!


推荐阅读