Android Room ilişkileri kullanarak arama ve filtreleme, birden çok tabloyu sorgulama
Repo aşağıdadır, eğer bir talepte bulunmak istiyorsanız lütfen yorumları ekleyin.
PokemonApp'ım için bir Oda veritabanı oluşturdum Veritabanını Pokemon adı ve Pokemon türlerine göre filtreleyip arayabilmek istiyorum.
Pokemon varlığım için bir tablom, PokemonType varlığı için bir tablo ve PokemonTypeJoin varlığı için bir bağlantı tablosuna sahibim, ayrıca bir Pokemon varlığını yerleştiren ve bununla PokemonType varlıkları listesi arasında bir ilişki tanımlayan bir veri sınıfı PokemonWithTypes var.
Pokemon varlığı:
@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 varlığı:
@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 varlığı:
@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 sınıfı
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>
)
bu yapı verildiğinde, aşağıdaki sorguyu kullanarak tüm PokemonWithTypes'i pokemon_name ile alabilir ve arayabilirim:
@Transaction
@Query("SELECT * FROM pokemon WHERE pokemon_name LIKE :search ORDER BY pokemon_id ASC")
fun getPokemonWithTypes(search: String?): LiveData<List<PokemonWithTypes>>
ancak şimdi PokemonWithTypes.types'ten herhangi birinin filtreler listesindeki belirli bir türle eşleştiği PokemonWithTypes döndüren bir filtreyi (dizge listesi) nasıl ekleyebilirim?
Yani 3 Pokemon verildi (kısalık için bazı veriler kaldırıldı)
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)])
Şu anda tüm Pokemonları alıyorum ve pokemon_name ile arama yapabiliyorum, ancak sadece su türlerini veya sadece çim türlerini gösterebilmek istiyorum.
Bunun gibi bir sorgu ile bir dizi listesi yerine bir dizeyi filtrelemeyi denedim
@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>>
ama işe yaramadı
burada her şeyi kontrol edebilirsiniz https://github.com/martipello/PokeApp/tree/add_filters
Yanıtlar
@ İlişki ek açıklamasının bu kullanım durumu için tasarlanmadığını düşünüyorum. Filtrelenmiş bir alt kümeyi değil, yalnızca TÜM ilişkili türleri döndürmek için tasarlanmıştır. Sanırım 3 seçeneğiniz var:
- Sadece KOTLIN ile filtre:
pokemonWithTypes.filter { it.types.contains("GRASS") }
. 10000'den fazla pokemon kaydınız olmadığını varsayıyorum, bu yüzden performans bir sorun değil. - Bir birleştirme sorgusu yazın. Bence bu ihmal edilebilir performans kazancı için daha fazla çaba.
- Veritabanı Görünümlerini şu şekilde kullanın: https://issuetracker.google.com/issues/65509934. Bu daha statik ve her tür için bir görünüm yazmanız gerekecek.