android - Android Room 搜索和过滤使用关系,查询多个表
问题描述
如果您想发出拉取请求,请在下面添加评论。
我为我的 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)])
我目前得到所有口袋妖怪并且可以通过口袋妖怪名称搜索但我希望能够只显示水类型或只显示草类型欢迎任何想法,
我尝试使用这样的查询过滤字符串而不是字符串列表
@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
解决方案
我认为 @Relation 注释不是为该用例设计的。它仅旨在返回所有相关类型,而不是过滤的子集。我认为你有3个选择:
- 只需使用 Kotlin: 过滤即可
pokemonWithTypes.filter { it.types.contains("GRASS") }
。我假设您的口袋妖怪记录不超过 10000 条,因此性能不是问题。 - 编写一个连接查询。我认为这是为了获得微不足道的性能提升而付出的更多努力。
- 按照以下方式使用数据库视图:https ://issuetracker.google.com/issues/65509934 。这更加静态,您必须为每种类型编写一个视图。
推荐阅读
- reactjs - React App localhost:3000 徽标不旋转
- karate - 如何在空手道 UI 自动化的活动浏览器会话中打开和关闭下一个/新选项卡
- leaflet - Leaflet 多边形部分(例如填充与轮廓)相对于其他图层的绘制顺序
- javascript - 尝试构建服务器端渲染角度 9 时出错
- javascript - 计算数组对象中的值的总和
- javascript - API 在待处理状态下响应的时间比在 chrome 网络选项卡中显示的时间长
- javascript - 如何使用 aws-amplify 从反应 Web 应用程序以推送通知的形式发送数据以反应本机应用程序?
- flutter - Flutter 网格视图滚动到底部
- mysql - MySQL 选择唯一索引而不是单列索引
- sql-server - 如何防止并发 T-SQL 事务中的死锁?