【问题标题】:Android room one to many and compute valuesAndroid房间一对多和计算值
【发布时间】:2021-06-25 16:03:03
【问题描述】:

我在房间里有一对多的关系。 我需要获取数据列表并计算每个对象的一个​​属性作为金额的总和。 我可以为此写一个查询吗?还是我必须遍历代码中的值?

更新


@Entity(tableName = "account_table")
class AccountModel(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    var name: String,
    var bankNumber: String,
    var amount: Double
)


@Entity(tableName = "spent_table")
data class SpentModel(
    var amount: Double,
    var title: String,
    var description: String,
    var date: String?,
    var accountId: Int,
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
)

data class AccountWithSpent(
    @Embedded val account: AccountModel,
    @Relation(
        parentColumn = "id",
        entityColumn = "accountId"
    )
    val spent: List<SpentModel>
)

AccountWithSpent 是我的数据的一对多关系,我想从花费中获取所有金额并将其存储到帐户对象金额属性。

【问题讨论】:

    标签: android sql android-room relation


    【解决方案1】:

    我可以为此写一个查询吗?

    是的

    或者我必须遍历代码中的值?

    不,但你可以。

    注意虽然可能有用的内容您可能希望直接进入底部并阅读附加/更正部分。

    假设您想在检索一个或多个 AccountWithSpent 对象时获得所花费金额的总和,那么您可以在 AccountWithSpent 中为此包含一个 val/字段,例如:-

    data class AccountWithSpent(
        @Embedded val account: AccountModel,
        @Relation(
            parentColumn = "id",
            entityColumn = "accountId"
        )
        val spent: List<SpentModel>,
        val sumOfSpent: Double /*<<<<< ADDED for SUM*/
    )
    

    然后您可以进行查询,例如:-

    @Transaction
    @Query("SELECT *, (SELECT sum(spent_table.amount)  FROM spent_table WHERE spent_table.accountId = a.id) AS sumOfSpent   FROM account_table AS a")
        fun getAccountWithSpent(): List<AccountWithSpent>
    
    • AS sumOfSpent 很重要,它将要从中获取数据的列命名为与 POJO 中的字段名称相同,它们必须匹配。
    • AS a 在子查询的 WHERE 子句中使用时消除 id 列的歧义 ((SELECT sum(spent_table.amount) FROM spent_table WHERE spent_table.accountId = a.id))
      • 即account_table 和 used_table 都有一个 id 列。所以使用 a.id 会强制使用 account_table id。

    你也可以有这样的查询:-

    @Transaction
    @Query("SELECT account_table.*, sum(spent_table.amount) AS sumOfSpent FROM account_table JOIN spent_table ON account_table.id = spent_table.accountId GROUP BY account_table.id")
    fun getAccountWithSpentV2(): List<AccountWithSpent>
    
    • 这不使用子查询,而是加入表并使用 GROUP BY 将行分组到帐户中。
    • 为了抑制 Room 发出警告的未使用列(来自花费表),account_table.* 用于定义输出列(即仅来自帐户表的列)
      • Room 再次从账户构建底层的 Spent 对象

    替代方案

    如果您只想要带有 Sum 的 Account 而不是底层 Spent 对象的 List,那么您可以使用以下内容:-

    data class AccountWithSumOfSpent(
        @Embedded
        val account: AccountModel,
        val sumOfSpent: Double
    )
    

    与:-

    @Query("SELECT *, sum(spent_table.amount) AS sumOfSpent FROM account_table JOIN spent_table ON account_table.id = spent_table.accountId GROUP BY account_table.id")
    fun getAccountWithSumofSpent(): List<AccountWithSumOfSpent>
    
    • 注意 @Transaction 不是必需的,因为所有数据都是由单个查询提取的

      • 子查询嵌入在主查询中。但是,当使用 @Relation Room 时,除了主查询之外,它还会构建和执行查询,因此它为什么会警告使用 @Transaction

    使用这两种方法的工作示例

        /* ADD 1 Account with 3 Spends (totalling $100.00) */
        val account1Id = dao.insert(AccountModel(0,"BANKX","000000",0.00)).toInt()
        dao.insert(SpentModel(30.00,"SPEND1","BUYA","2021-06-25",account1Id))
        dao.insert(SpentModel(30.00,"SPEND2","BUYB","2021-06-24",account1Id))
        dao.insert(SpentModel(40.00,"SPEND3","BUYC","2021-06-23",account1Id))
    
        /* Extract and Log using first method (Account, with Sum and with all Spends) */
        for(a: AccountWithSpent in dao.getAccountWithSpent()) {
            Log.d("ACCNTINFO","Account Name is ${a.account.name} Bank Number is ${a.account.bankNumber} SUM of Spend is ${a.sumOfSpent}")
            //Log.d("ACCNTINFO","Account Name is ${a.account.name} Bank Number is ${a.account.bankNumber}")
            for(s: SpentModel in a.spent) {
                Log.d("ACCNTINFO","Title is \t${s.title} Description is ${s.description} Date is ${s.date} Amount is ${s.amount}")
            }
        }
        /* Extract and Log using second method (no Spends) */
        for(a: AccountWithSumOfSpent in dao.getAccountWithSumofSpent()) {
            Log.d("ACCNTINFO", "Account Name is ${a.account.name} Bank Number is ${a.account.bankNumber} SUM of Spend is ${a.sumOfSpent}")
        }
    

    结果

    日志包括:-

    2021-06-26 07:58:55.265 D/ACCNTINFO: Account Name is BANKX Bank Number is 000000 SUM of Spend is 100.0
    2021-06-26 07:58:55.265 D/ACCNTINFO: Title is   SPEND1 Description is BUYA Date is 2021-06-25 Amount is 30.0
    2021-06-26 07:58:55.265 D/ACCNTINFO: Title is   SPEND2 Description is BUYB Date is 2021-06-24 Amount is 30.0
    2021-06-26 07:58:55.265 D/ACCNTINFO: Title is   SPEND3 Description is BUYC Date is 2021-06-23 Amount is 40.0
    
    
    2021-06-26 07:58:55.268 D/ACCNTINFO: Account Name is BANKX Bank Number is 000000 SUM of Spend is 100.0
    

    补充/更正

    我需要获取数据列表并计算每个对象的一个​​属性作为金额的总和。 AccountWithSpent 是我的数据的一对多关系,我想从花费中获取所有金额并将其存储到帐户对象金额属性。

    我没有正确阅读以上内容,因此根据您的原始 AccountWithSpent,您可以使用:-

    @Transaction
    @Query("SELECT account_table.id,account_table.name, account_table.bankNumber, sum(spent_table.amount) AS amount FROM account_table JOIN spent_table ON account_table.id = spent_table.accountId GROUP BY account_table.id")
    fun getAccountWithSpent(): List<AccountWithSpent>
    

    AccountModel 的金额将被相应地填充。

    但是,需要注意的是,数据库中的数量仍然是原来的,不会改变。一个反问,你需要存入数据库的金额,因为它总是可以计算的吗?

    也许 AccountModel 有:-

    .....
    @Ignore 
    var amount: Double
    

    如果您想要数据库中的金额,那么也许您应该始终维护数据库中的金额。如果是这样,那么您不妨考虑在添加/删除或更新支出时使用触发器以自动调整金额(如果是这样,那将是另一个问题)。 p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多