【问题标题】:Usage of room database querying with IN operator providing list of Enums使用提供枚举列表的 IN 运算符查询房间数据库
【发布时间】:2020-11-18 08:26:56
【问题描述】:

使用枚举列表作为参数查询房间数据库仅当列表中提供单个枚举时才会产生结果,而当列表中存在多个枚举时不返回结果。给定查询中单个 Enum 的列表,返回的结果将仅是与该 Enum 完全匹配的结果,并且没有包含该 Enum 和其他 Enum 组合的结果。

但是,根据this post,应该返回匹配包含元素的结果。此外,据我所知,android documentation 概述了预期的行为是相同的。我发现 this issue tracked 具有非常相似的性质,虽然不完全导致合并到 AOSP,但对我的问题几乎没有提供任何见解。

任何帮助表示赞赏,代码如下:

枚举

enum class Type(val type: String) {
    NORMAL("normal"),
    FIGHTING("fighting"),
    FLYING("flying"),
    POISON("poison"),
    GROUND("ground"),
    ROCK("rock"),
    BUG("bug"),
    GHOST("ghost"),
    FIRE("fire"),
    WATER("water"),
    GRASS("grass"),
    ELECTRIC("electric"),
    PSYCHIC("psychic"),
    ICE("ice"),
    DRAGON("dragon"),
    FAIRY("fairy"),
    STEEL("steel");
}

@Query("SELECT * from pokemon_table WHERE types IN (:typesList)")
fun getFilteredPokemon(typesList: List<Type>): LiveData<List<Pokemon>>

类型转换器

@TypeConverter
fun fromString(value: String?): List<Type>? {
    val listType = object : TypeToken<List<Type>>() {}.type
    return Gson().fromJson(value, listType)
}

@TypeConverter
fun fromList(list: List<Type>?): String? {
    val listType = object : TypeToken<List<Type>>() {}.type
    return Gson().toJson(list, listType)
}

这是数据库的截图,用于说明存储的值,使用listOf(Type.FIRE) 查询将返回charmeleon,而不是charizard。

【问题讨论】:

  • 只是为了澄清您对 IN 运算符的期望 - 如果您的数据库只有这 6 行,您的查询是否应该返回带有 listOf(Type.FIRE,Type.GRASS) 的内容?
  • 只有上面的 6 行,用火和草查询我希望所有 6 个结果。
  • 据我了解,Room 在查询中使用 TypeConverter 只是为了将您的 List 转换为 String,然后 Room 将修改后的查询发送到 sqlite。那么确实["FIRE"]中的"[FIRE]"给出true,而["FIRE"]中的["FIRE", "FLYING"]给出false。老实说,我不知道您想要什么的简单决定(无需更改表的结构以使用关系而不是 JSON 字符串)。
  • 正确,这可以修改为使用类型表并以返回我想要的方式构造查询。我现在想到的问题是 IN 是否与 LIKE 有什么不同,以及它的用途是什么。感谢您的帮助。

标签: android kotlin android-room


【解决方案1】:

正如sergiy-tikhonov 在他的comment 中标识的那样,sql IN 运算符仅返回与提供的列表中的一次匹配的结果。

我已经设法通过为每个条目分配两个“类型”列而不是包含“类型”列表的单个列来纠正我的问题(因为每个口袋妖怪只能有两种类型,所以不使用表之间的关系)。为每个条目分配主要和次要类型允许我使用单个类型列表查询两列:

@Query("SELECT * FROM pokemon_table WHERE type_primary IN (:types) UNION SELECT * FROM pokemon_table WHERE type_secondary IN (:types)")
fun getFilteredPokemon(types: List<Type>): LiveData<List<Pokemon>>

我不得不修改 TypeConverter 来实现这一点:

class TypeConverter {
    @TypeConverter fun fromString(value: String) = Type.getTypeByName(value)
    @TypeConverter fun fromList(type: Type) = type.type
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2018-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多