Recherche et filtrage de salle Android à l'aide de relations, interrogation de plusieurs tables
Le dépôt est ci-dessous si vous souhaitez émettre une demande d'extraction, veuillez inclure des commentaires.
J'ai créé une base de données de pièces pour mon PokemonApp. Je souhaite pouvoir filtrer et rechercher dans la base de données en fonction du nom et des types de Pokémon.
J'ai une table pour mon entité Pokemon, une table pour l'entité PokemonType et une table de jonction pour l'entité PokemonTypeJoin, j'ai aussi une classe de données PokemonWithTypes qui embarque une entité Pokemon et définit une relation entre celle-ci et une liste d'entités PokemonType.
Entité Pokémon :
@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"
Entité 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"
Entité 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"
Classe 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>
)
étant donné cette structure, je peux obtenir et rechercher par pokemon_name tous les PokemonWithTypes en utilisant la requête suivante :
@Transaction
@Query("SELECT * FROM pokemon WHERE pokemon_name LIKE :search ORDER BY pokemon_id ASC")
fun getPokemonWithTypes(search: String?): LiveData<List<PokemonWithTypes>>
mais comment puis-je maintenant ajouter un filtre (liste de chaînes) qui ne renvoie que PokemonWithTypes où l'un des PokemonWithTypes.types correspond à un type donné dans la liste des filtres ?
Donc, étant donné 3 Pokémon (certaines données ont été supprimées par souci de brièveté)
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)])
Je reçois actuellement tous les Pokémon et je peux rechercher par pokemon_name mais j'aimerais pouvoir montrer uniquement les types d'eau ou uniquement les types d'herbe, toutes les idées sont les bienvenues,
J'ai essayé de filtrer simplement sur une chaîne au lieu d'une liste de chaînes avec une requête comme celle-ci
@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>>
mais ça n'a pas marché
vous pouvez consulter l'intégralité icihttps://github.com/martipello/PokeApp/tree/add_filters
Réponses
Je pense que l'annotation @Relation n'est pas conçue pour ce cas d'utilisation. Il est uniquement conçu pour renvoyer TOUS les types associés, pas un sous-ensemble filtré. Je pense que tu as 3 possibilités :
- Il suffit de le filtrer avec Kotlin :
pokemonWithTypes.filter { it.types.contains("GRASS") }
. Je suppose que vous n'avez pas plus de 10 000 enregistrements de pokémons, donc les performances ne sont pas un problème. - Rédigez une requête de jointure. Je pense que c'est plus d'effort pour un gain de performance négligeable.
- Utilisez les vues de base de données selon :https://issuetracker.google.com/issues/65509934. Ceci est plus statique et vous devrez écrire une vue pour chaque type.