【问题标题】:Android Room search and filter using relations, query multiple tablesAndroid Room 搜索和过滤使用关系,查询多个表
【发布时间】:2020-08-16 19:00:18
【问题描述】:

如果您想发出拉取请求,请在下方包含 repo。

我为我的 PokemonApp 创建了一个 Room 数据库,我希望能够根据 Pokemon 名称和 Pokemon 类型过滤和搜索数据库。

我有一个用于我的 Pokemon 实体的表,一个用于 PokemonType 实体的表和一个用于 PokemonTypeJoin 实体的连接表,我还有一个数据类 PokemonWithTypes,它嵌入了一个 Pokemon 实体并定义了它与 PokemonType 列表之间的关系实体。

口袋妖怪实体:

    @TypeConverters(RoomStringListConverter::class)
    @Entity
    data class Pokemon(
        @NotNull
        @PrimaryKey
        @ColumnInfo(name = POKEMON_ID)
        var id: Int,
    
        @ColumnInfo(name = POKEMON_NAME)
        var name: String,
    
        @ColumnInfo(name = POKEMON_URL)
        var url: String,
    
        @ColumnInfo(name = POKEMON_WEIGHT)
        val weight: Int,
    
        @ColumnInfo(name = POKEMON_HEIGHT)
        val height: Int,
    
        @ColumnInfo(name = POKEMON_SPECIES)
        var species: String,
    
        @ColumnInfo(name = POKEMON_MOVES)
        val moves: List<String>
    
    ) 

    const val POKEMON_ID: String = "pokemon_id"
    const val POKEMON_NAME: String = "pokemon_name"
    const val POKEMON_URL: String = "pokemon_url"
    const val POKEMON_HEIGHT: String = "pokemon_height"
    const val POKEMON_WEIGHT: String = "pokemon_weight"
    const val POKEMON_MOVES: String = "pokemon_moves"
    const val POKEMON_SPECIES: String = "pokemon_species"

PokemonType 实体:

    @Entity
    data class PokemonType (
    
        @NotNull
        @PrimaryKey
        @ColumnInfo(name = POKEMON_TYPE_ID)
        var id: Int,
    
        @ColumnInfo(name = POKEMON_TYPE_NAME)
        var name: String,
    
        @ColumnInfo(name = POKEMON_TYPE_SLOT)
        var slot: Int
    
    )

    const val POKEMON_TYPE_ID: String = "type_id"
    const val POKEMON_TYPE_NAME: String = "type_name"
    const val POKEMON_TYPE_SLOT: String = "type_slot"

PokemonTypesJoin 实体:

    @Entity(primaryKeys = [POKEMON_ID, POKEMON_TYPE_ID])
    class PokemonTypesJoin(
        @NotNull
        @ColumnInfo(name = POKEMON_ID, index = true)
        val pokemon_id: Int,
    
        @NotNull
        @ColumnInfo(name = POKEMON_TYPE_ID, index = true)
        val pokemon_type_id: Int
    
    )
    
    const val POKEMON_ID: String = "id"
    const val POKEMON_TYPE_ID: String = "type_id"

PokemonWithTypes 类

    data class PokemonWithTypes(
        @Embedded
        val pokemon: Pokemon,
        @Relation(
            parentColumn = Pokemon.POKEMON_ID,
            entity = PokemonType::class,
            entityColumn = PokemonType.POKEMON_TYPE_ID,
            associateBy = Junction(
                value = PokemonTypesJoin::class,
                parentColumn = PokemonTypesJoin.POKEMON_ID,
                entityColumn = PokemonTypesJoin.POKEMON_TYPE_ID
            )
        )
        val types: List<PokemonType>
    )

鉴于此结构,我可以使用以下查询按 pokemon_name 所有 PokemonWithTypes 获取和搜索:

@Transaction
@Query("SELECT * FROM pokemon WHERE pokemon_name LIKE :search ORDER BY pokemon_id ASC")
fun getPokemonWithTypes(search: String?): LiveData<List<PokemonWithTypes>>

但是我现在如何添加一个过滤器(字符串列表),它只返回 PokemonWithTypes,其中任何 PokemonWithTypes.types 与过滤器列表中的给定类型匹配?

所以给定 3 个口袋妖怪(为简洁起见,删除了一些数据)

PokemonWithTypes(pokemon=Pokemon(id=1, name=bulbasaur, types=[PokemonType(id=4, name=poison, slot=2), PokemonType(id=12, name=grass, slot=1)])
PokemonWithTypes(pokemon=Pokemon(id=4, name=charmander, types=[PokemonType(id=10, name=fire, slot=2), PokemonType(id=12, name=grass, slot=1)])
PokemonWithTypes(pokemon=Pokemon(id=7, name=squirtle, types=[PokemonType(id=11, name=water, slot=2), PokemonType(id=12, name=grass, slot=1)])

我目前获得所有口袋妖怪,可以按 pokemon_name 搜索,但我希望能够仅显示水类型或仅显示草类型,欢迎提出任何想法,

我尝试只过滤一个字符串,而不是使用这样的查询的字符串列表

@Transaction
@Query("SELECT * FROM pokemon, pokemonType WHERE type_name LIKE :filter AND pokemon_name LIKE :search ORDER BY pokemon_id ASC")
fun getPokemonWithTypes(search: String?, filter: String): LiveData<List<PokemonWithTypes>>

但是没用

你可以在这里查看完整的东西https://github.com/martipello/PokeApp/tree/add_filters

【问题讨论】:

    标签: android sql android-room


    【解决方案1】:

    我认为@Relation 注释不是为该用例设计的。它仅旨在返回所有相关类型,而不是过滤的子集。我认为你有 3 个选择:

    1. 只需使用 Kotlin 过滤它:pokemonWithTypes.filter { it.types.contains("GRASS") }。我假设您的口袋妖怪记录不超过 10000 条,因此性能不是问题。
    2. 编写一个连接查询。我认为这是为了获得微不足道的性能提升而付出的更多努力。
    3. 按照https://issuetracker.google.com/issues/65509934 使用数据库视图。这更加静态,您必须为每种类型编写一个视图。

    【讨论】:

    • 谢谢你,我会在视图模型中过滤它
    • 我对 2 真的很感兴趣。使用自定义连接(没有 @Relation)返回的 pojo 会是什么样子谢谢
    猜你喜欢
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多