एंड्रॉइड रूम खोज और संबंधों का उपयोग करके फ़िल्टर करें, कई तालिकाओं को क्वेरी करें

Aug 17 2020

यदि आप पुल अनुरोध जारी करना चाहते हैं तो रेपो नीचे है, कृपया टिप्पणी शामिल करें।

मैंने अपने PokemonApp के लिए एक कक्ष डेटाबेस बनाया है मैं चाहता हूं कि मैं 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

जवाब

1 CarsonHolzheimer Aug 17 2020 at 08:05

मुझे लगता है कि @Relation एनोटेशन उस उपयोग के मामले के लिए डिज़ाइन नहीं किया गया है। यह केवल सभी संबंधित प्रकारों को वापस करने के लिए डिज़ाइन किया गया है, न कि एक फ़िल्टर किए गए सबसेट। मुझे लगता है कि आपके पास 3 विकल्प हैं:

  1. बस इसे कोटलिन के साथ फ़िल्टर करें pokemonWithTypes.filter { it.types.contains("GRASS") }:। मुझे लगता है कि आपके पास पोकेमॉन के 10000 से अधिक रिकॉर्ड नहीं हैं, इसलिए प्रदर्शन एक मुद्दा नहीं है।
  2. ज्वाइन क्वैश्चन लिखिए। मुझे लगता है कि नगण्य प्रदर्शन लाभ के लिए यह अधिक प्रयास है।
  3. डेटाबेस दृश्य का उपयोग करें: https://issuetracker.google.com/issues/65509934। यह अधिक स्थिर है और आपको हर प्रकार के लिए एक दृश्य लिखना होगा।