【问题标题】:RoomDB - JOIN query for which the result is a list of data types with a field whose value is a multiplication of 2 tables fieldsRoomDB - JOIN 查询,其结果是一个数据类型列表,其中一个字段的值是 2 个表字段的乘积
【发布时间】:2021-06-22 16:34:00
【问题描述】:

假设我的 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 表,并将每个金额与 value 表中的相应值行连接起来(使用来自amounttype 交叉引用value 表上的valueType 字段),方法是将amount 字段与value 字段相乘,最终得到如下对象:

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

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

像这样创建一个连接的数据类:

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 操作定义关系)。

【问题讨论】:

    标签: android sql android-room


    【解决方案1】:

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

    首先要加入一个类:-

    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>
    

    如果您也想要 Value,由于列重复/不明确,它会稍微复杂一些,但您可以使用:-

    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 子句来消除各个列的歧义。由于金额列上没有使用前缀,因此可以使用金额。*(第二道)。

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

    【讨论】:

    • 塔迈克 - 我会在早上检查这个,感谢答案(以及上一个问题 - 为花时间干杯)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 2013-03-03
    • 1970-01-01
    • 2012-07-12
    • 2013-03-13
    相关资源
    最近更新 更多