Android 房间如何增加计数字段和更新特定行字段
Android room how to increment count field and updating specific row fields
我正在实施以下架构来计算用户的按钮点击次数。例如,如果用户点击苹果按钮,我想将类型存储为主键,这将是一个唯一的条目,后跟用户点击苹果按钮的次数计数,对于每一个我也会保存与这些点击相关的时间。因此,我正在尝试学习房间数据库,并想了解如何使用新的关联计数和时间戳更新唯一的水果类型行。我是否必须查询 table 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()
}
我相信以下内容可以满足您的需求:-
@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());
结果:-
即当更新计数递增并且当前时间已相应设置后,插入计数和时间为 0。所以不需要获取数据然后应用(只要你知道你应该知道的类型,如果它等同于按钮)。
补充评论
I would still need to insert once before updating and incrmenting ! Is there a shorter version to insertorupdate at the same time.
是的,也许吧。但是,如果您有按钮,那么我建议您在知道应该有按钮时插入。
如果应用程序针对 android versions that have SQLite version 3.24.0 (Android API 30+ version 11+) then you could use an 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 OR REPLACE,只需使用:-
@Insert(onConflictStategy = OnConflictStrategy.REPLACE)
fun insert(ClickEntity("the_type",the_new_count,the_current_timestamp)
但是 您必须检索计数。
HOWEVER 更复杂的解决方案可能是使用子查询为类型获取计数 + 1。这很复杂,因为第一次插入时没有计数。这可以使用 SQLite coalesce
函数解决。这将需要 @Query 因为 @Insert 需要一个 Entity 对象。因此,插入或替换 (更新但实际上删除并插入以执行更新) 的解决方案可能是:-
@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,因此添加了合并函数 returns -1 和 1,因此计数为 0新行。
- 使用 SQLite 的
strftime
函数获取当前时间(精确到秒)并将其乘以 1000 使其与 Android 时间戳(增加毫秒)内联。
- 如果类型存在,它将用另一行替换该行:-
- 从现有行中找到计数并加 1
示例(插入或替换选项):-
根据上述代码,除了上述 Dao 的 changes/additions(不是 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 显示了 CURRENT_TIMESTAMP 的存储方式,这会导致问题。
- Pear 仅使用 strftime('%s','now') 即没有毫秒
- 如您所见,葡萄和杏都符合预期,即计数已增加。
您可以执行以下操作
@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)
我正在实施以下架构来计算用户的按钮点击次数。例如,如果用户点击苹果按钮,我想将类型存储为主键,这将是一个唯一的条目,后跟用户点击苹果按钮的次数计数,对于每一个我也会保存与这些点击相关的时间。因此,我正在尝试学习房间数据库,并想了解如何使用新的关联计数和时间戳更新唯一的水果类型行。我是否必须查询 table 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()
}
我相信以下内容可以满足您的需求:-
@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());
结果:-
即当更新计数递增并且当前时间已相应设置后,插入计数和时间为 0。所以不需要获取数据然后应用(只要你知道你应该知道的类型,如果它等同于按钮)。
补充评论
I would still need to insert once before updating and incrmenting ! Is there a shorter version to insertorupdate at the same time.
是的,也许吧。但是,如果您有按钮,那么我建议您在知道应该有按钮时插入。
如果应用程序针对 android versions that have SQLite version 3.24.0 (Android API 30+ version 11+) then you could use an 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 OR REPLACE,只需使用:-
@Insert(onConflictStategy = OnConflictStrategy.REPLACE)
fun insert(ClickEntity("the_type",the_new_count,the_current_timestamp)
但是 您必须检索计数。
HOWEVER 更复杂的解决方案可能是使用子查询为类型获取计数 + 1。这很复杂,因为第一次插入时没有计数。这可以使用 SQLite coalesce
函数解决。这将需要 @Query 因为 @Insert 需要一个 Entity 对象。因此,插入或替换 (更新但实际上删除并插入以执行更新) 的解决方案可能是:-
@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,因此添加了合并函数 returns -1 和 1,因此计数为 0新行。
- 使用 SQLite 的
strftime
函数获取当前时间(精确到秒)并将其乘以 1000 使其与 Android 时间戳(增加毫秒)内联。
- 如果类型存在,它将用另一行替换该行:-
- 从现有行中找到计数并加 1
示例(插入或替换选项):-
根据上述代码,除了上述 Dao 的 changes/additions(不是 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 显示了 CURRENT_TIMESTAMP 的存储方式,这会导致问题。
- Pear 仅使用 strftime('%s','now') 即没有毫秒
- 如您所见,葡萄和杏都符合预期,即计数已增加。
您可以执行以下操作
@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)