我的问题是这个问题的延伸(也是我的:)) - > Room composite Primary Key link to Foreign Key 所以,如果我有这个课程:
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}"
?
答案 0 :(得分:6)
注释@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。因此,我们在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查询一样,必须进行映射,以免重复数据行或错误分配数据,具体取决于联接的复杂性。我建议将数据移至键值映射,然后加入所有togheter过滤重复的键。在这种情况下,我们将映射到我们在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实体以获取最新数据,我对此将有不好的经验。
我知道它不是纯粹的,但是架构是受尊重的,并且查询/映射过程不需要大量的工作和维护。希望对您有帮助!
答案 1 :(得分:0)
我找到了一些解决方法。但这会影响性能。 您需要在关系字段中添加特殊的吸气剂,以使用复合主键的其他部分过滤结果。
对于您来说,它看起来像:
public class FoodWithIngredients {
@Embedded
private Food food;
@Relation(parentColumn = "id", entityColumn = "food_id", entity =
Ingredient.class)
private List<Ingredient> mIngredients;
public List<Ingredient> getIngredients() {
List<Ingredient> result = List<Ingredient>();
for (ingredient in mIngredients) {
if (ingredient.foodLanguageId == food.languageId) {
result.add(ingredient);
}
}
return result;
}
}
答案 2 :(得分:0)
从 Room 2.4.0-alpha04 开始,您可以编写 DAO 方法,为 1:N 关系返回 Map<Entity, List<Relation>>
。这使您能够编写 JOIN
查询,指定如何获取关系,可选择指定 WHERE
和 ORDER BY
子句。