android room如何增加计数字段和更新特定行字段

vu8f3i0k  于 2021-08-25  发布在  Java
关注(0)|答案(2)|浏览(759)

我实现了以下模式,用于计算用户的按钮点击次数。例如,如果用户单击apple按钮,我希望将类型存储为主键,这将是一个唯一的条目,后面是用户点击apple按钮的次数计数,对于每一次点击,我还将节省与这些点击相关的时间。所以我试图学习room数据库,想了解如何使用新的关联计数和时间戳更新唯一的水果类型行。我需要查询这个表吗 getByType(type) 获取现有数据条目,然后每次使用新的计数和时间戳值对其进行更新,或者是否有更好的方法使用room api进行更新

@Entity
 data class ClickEntity(
   @PrimaryKey
   val type: String,
   val clickCount: Int? = null,
   val clickTime: Long? = null
 )

 @Dao
internal interface ClickEntityDao {
@Query("SELECT * FROM ClickEntity ORDER BY type")
fun getAll(): List<ClickEntity>

@Query("SELECT * FROM ClickEntity WHERE type=:type")
fun getByType(entity: ClickEntity): ClickEntity

// QUESTION: type, count, time -> how do I increment counter and update time while updating an existing entry
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun update(entity: ClickEntity) 

@Query("DELETE FROM ClickEntity")
fun clear()
}
2w3kk1z5

2w3kk1z51#

您可以执行以下操作

@Entity
 data class ClickEntity(
   @PrimaryKey
   val type: String,
   val clickCount: Int = 0,
   val clickTime: Long = System.currentTimeMillis()
 )

然后增加

@Query("UPDATE ClickEntity SET clickCount = clickCount + 1, clickTime = CURRENT_TIMESTAMP WHERE type=:type")
fun incrementClick(type: String)
t3psigkw

t3psigkw2#

我相信以下几点可以满足您的需求:-

@Query("UPDATE ClickEntity SET clickCount = clickCount + 1, clickTime = :clickTime WHERE type=:type")
fun incrementClick(type: String, clickTime: Long)

例如:-

dao.insert(ClickEntity("Apple",0,0))
    dao.incrementClick("Apple",System.currentTimeMillis());

结果:-

i、 e.在更新计数增加且当前时间相应设置后,当插入计数和时间为0时。因此,无需获取数据然后应用(只要您知道应该使用的类型,如果它等同于按钮)。
补充再评论
我仍然需要在更新和插入之前插入一次!是否有一个较短的版本可同时插入更新。
是的,也许吧。然而,如果你有一个按钮,那么我建议在你知道应该有按钮时插入。
如果应用程序针对的是具有sqlite版本3.24.0(android api 30+版本11+)的android版本,那么您可以使用upsert(插入带有on conflict()do update子句)。
例如

@Query("INSERT INTO clickEntity VALUES(:type,0,:clickTime) ON CONFLICT(type) DO UPDATE SET clickCount = clickCount +1, clickTime = :clickTime ")
fun insertOrUpdate(type: String, clickTime: Long)

注意:上面的代码没有经过测试,但是显示了一个语法错误(可能是因为目标android版本)。
另一种选择是使用插入或替换,这只是使用:-

@Insert(onConflictStategy = OnConflictStrategy.REPLACE)
fun insert(ClickEntity("the_type",the_new_count,the_current_timestamp)

但是你必须找回计数。
但是,更复杂的解决方案可能是使用子查询获取类型的计数+1。这很复杂,因为第一次插入时没有计数。这可以使用sqlite解决 coalesce 功能。这需要@query,因为@insert需要一个实体对象。因此,插入或替换(更新但实际删除和插入以执行更新)的解决方案可以是:-

@Query("INSERT OR REPLACE INTO clickentity VALUES(:type,coalesce((SELECT clickCount FROM clickEntity WHERE type = :type),-1) + 1,strftime('%s','now') * 1000)")
fun insertOrReplace(type: String)

因此:-
如果该类型不存在,它将插入一个新行,以便:
尝试获取类型的clickcount列的当前值,但由于不存在此类行,因此返回null,因此coalesce函数返回-1,并添加1,因此新行的计数为0。
使用sqlite的 strftime 函数,并将其乘以1000,使其与android时间戳内联(添加毫秒)。
如果该类型存在,则将用另一行替换该行,以便:
从现有行中查找计数并添加1
示例(插入或替换选项):-
根据上述代码,除了上述dao的更改/添加之外,还添加了以下内容(不是upsert):-

// Adds new
    dao.insert(ClickEntity("Grape",0, System.currentTimeMillis()))
    // Updates (cheated with clickCount knowing it would be 1)
    dao.insert(ClickEntity("Grape",1,System.currentTimeMillis()))
    // Adds new
    dao.insertOrReplace("Apricot")
    // Updates
    dao.insertOrReplace("Apricot")

然后,数据库看起来像(所有android studio show):-

banana显示当前_时间戳是如何存储的,这将导致问题。
pear只使用strftime(“%s”、“now”),即没有毫秒
正如您所看到的,葡萄和杏都是预期的,即数量增加了。

相关问题