RoomDB - JOIN 查询,其结果是一个数据类型列表,其中一个字段的值是 2 个表字段的乘积

RoomDB - JOIN query for which the result is a list of data types with a field whose value is a multiplication of 2 tables fields

假设我的 RoomDB 有以下实体:

enum class Type {
    FOO,
    BAR
}

@Entity(
    tableName = "amount",
    primaryKeys = ["id", "type"]
)
data class Amount(
    val id: Long,
    val type: Type,
    val amount: Int
)

@Entity(
    tableName = "value",
    primaryKeys = ["id", "valueType"]
)
data class Value(
    val id: Long,
    val valueType: Type,
    val value: Int
)

我想做的是以某种方式,使用 SQL 查询(或者理想情况下是 RoomDB 注释...)查询 amount table,并将每个金额与相应的value table 中的值行(使用 amount 中的 type 交叉引用 value [= 上的 valueType 字段41=]) 通过将 amount 字段与 value 字段相乘得到如下对象:

data class ValueOfAmount(
    val type: Type,
    val valueOfAmount: Int // amount * value
)

我可以想办法做到这一点,但它需要在我的 repo 代码层中执行一些 JOIN “逻辑”,而我更愿意在查询层执行此操作(如果可能的话) ).

像这样创建连接数据class:

data class AmountWithValue(
    @Embedded
    val amount: Amount,
    @Relation(
        parentColumn = "type",
        entityColumn = "valueType"
    )
    val value: Value
)

从我的 dao 中公开一个函数来检索连接的数据:

@Query("SELECT * from amount")
suspend fun getAmountsWithValues() : List<AmountWithValue>

使用此函数,并将结果映射到 ValueOfAmount 个实例,如下所示:

val valueOfAmounts = dao.getAmountsWithValues().map { amountWithValue ->
    ValueOfAmount(
        amountWithValue.amount.type,
        amountWithValue.amount.amount * amountWithValue.value.value
    )
}

// Do stuff with value of amounts

我想知道是否有某种方法可以将该映射代码编码到 QUERY 本身(通过 SQL 或者,如果 RoomDB 有一些支持这种类型的注释,则更好复杂查询作为我的数据类型的注释 - 类似于它让我为简单的 JOIN 操作定义关系的方式)。

相信以下可能是您想要的:-

首先要加入Class:-

data class AmountWithCalculatedValue(
    @Embedded
    val amount: Amount,
    val calculatedValue: Int
)

然后是道:-

@Query("SELECT *,(amount * value) AS calculatedValue  FROM amount JOIN value ON amount.type = valueType")
    fun getAmountWithCalculatedValue(): List<AmountWithCalculatedValue>

如果您也想要值,由于 duplicate/ambiguous 列,它会稍微复杂一些,但您可以使用:-

data class AmountWithCalculatedValue(
    @Embedded
    val amount: Amount,
    val calculatedValue: Int,
    @Embedded(prefix = "_value_")
    val value: Value
)

有:-

@Query("SELECT amount.id, amount.amount, amount.type,value.id AS _value_id, value.id AS _value_value, value.valueType AS _value_valueType,(amount * value) AS calculatedValue  FROM amount JOIN value ON amount.type = valueType")
    fun getAmountWithCalculatedValue(): List<AmountWithCalculatedValue>

或:-

@Query("SELECT amount.*,value.id AS _value_id, value.id AS _value_value, value.valueType AS _value_valueType,(amount * value) AS calculatedValue  FROM amount JOIN value ON amount.type = valueType")
    fun getAmountWithCalculatedValue(): List<AmountWithCalculatedValue>
  • 使用 @Embedded 的前缀参数表示值将以前缀为前缀,因此您必须使用 AS 子句来消除各个列的歧义。由于金额列上没有使用前缀,因此可以使用金额。*(第二道)。

  • 我想说,对于一对一关系,使用@Relationship(与@Embedded 相反)可能比使用 JOIN 效率低一些。由于 Room 的工作方式,它从给定的查询中获取父项,然后通过单独的查询从父项中检索 @Relation,因此它推荐 @Transaction 的原因。