bal*_*ekg 7 android kotlin android-sqlite android-room
在我的应用程序中,用户可以在每个组合中使用多个过滤器来过滤他们的数据(仅应用一个、多个或不应用)。
在此之前,我只有一个过滤器,所以每次应用它时,我都在切换 DAO 方法。现在我有 6 个过滤器,所以有几十种组合,因此为每个组合创建一个方法是不可能的。我也不能大量修改我的数据库,因为它已经可供用户使用。
我当前的代码如下所示:
@Query("SELECT id, name, date FROM UserData")
fun getAll(): DataSource.Factory<Int, UserItem> //no filters
@Query("SELECT id, name, date FROM UserData WHERE name LIKE '%' || :search || '%'")
fun getAllFiltered(query: String): DataSource.Factory<Int, UserItem> //one filter applied
Run Code Online (Sandbox Code Playgroud)
有没有办法修改查询,以便所有过滤器组合都有一种方法?
更新:
这是我的数据类,我想过滤哪些实例:
@Entity(tableName = "UserItem")
data class UserItem(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Long? = null,
@ColumnInfo(name = "created_at")
val createdAt: Date,
@ColumnInfo(name = "is_uploaded")
val isUploaded: Boolean,
@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "item_sum")
val sum: Int = 0,
@ColumnInfo(name = "tags")
val tags: List<String> = listOf(),
)
Run Code Online (Sandbox Code Playgroud)
我想过滤/检查数字和布尔属性的相等性,检查列表属性是否包含指定的字符串。基本上,我希望能够过滤所有我能过滤的东西。如果不可能,我至少会对一些过滤器感到满意。
根据@CommonsWare 的评论,我尝试使用RawQuery来实现我想要的。
首先要做的是创建 Filters 数据类,该数据类将来将保存所有过滤器。删除一个或添加多个确实很容易。
data class Filters(
val query: String? = null,
val isUploaded: Boolean? = null,
// all the other filters
)
Run Code Online (Sandbox Code Playgroud)
将构建查询并从数据库返回结果的函数:
fun getAllFiltered(filters: Filters): DataSource.Factory<Int, UserItem> {
val conditions = mutableListOf<Pair<String, Any?>>()
with(filters) {
query?.let { conditions.add("name LIKE '%' || ? || '%'" to it) }
isUploaded?.let { conditions.add("is_uploaded = ${it.toInt()}" to null) }
// "subqueries" to filter specific field
}
if (conditions.isEmpty())
return getAll()
val conditionsMerged = conditions.joinToString(separator = " AND ") { it.first }
val bindArgs = conditions.mapNotNull { it.second }
val query = SimpleSQLiteQuery(
"SELECT id, name, date FROM UserData WHERE $conditionsMerged",
bindArgs.toTypedArray()
)
return getAllFiltered(query)
}
@RawQuery(observedEntities = [UserItem::class])
fun getAllFiltered(query: SupportSQLiteQuery): DataSource.Factory<Int, UserItem>
private fun Boolean.toInt() = if (this) 1 else 0
Run Code Online (Sandbox Code Playgroud)
我不知道它将如何执行,因为查询必须在运行时构建(但从我所做的一些测试来看,我没有注意到太多的性能损失),但优点是很容易添加其他过滤器或删除现有过滤器,如果仅应用多个过滤器中的一个,则创建的查询非常简单。
归档时间: |
|
查看次数: |
219 次 |
最近记录: |