Как я могу превратить список строк в предложения LIKE в Room Query? - PullRequest
0 голосов
/ 06 марта 2020

У меня есть таблица с именем games, в которой есть столбец с именем platforms, в котором содержится список сокращений платформы. Это список всех платформ, на которых вышла игра c. Вот пример одной из ячеек в platforms:

AMI,GG,SNES,CPC,AST,C64,SPEC,MAC,PS2,NES,3DO,ARC,XBGS,PS3N,PC,IPHN,DSI,HALC,PSPN,ANDR,

Пользователь может выбрать любое количество платформ, для которых он sh будет просматривать игры. Например, они могут выбрать просмотр игр для следующих платформ:

SNES, MAC, PC

Поэтому мне нужен способ программно построить запрос Room, который бы находил игры на выбранных платформах. Мне нужно как-то сгенерировать произвольное количество предложений LIKE и вставить их в запрос. Я попробовал следующее, но он не дал результатов:

private fun fetchLikeClauses(platformIndices: MutableSet<Int>): String {
    val sb = StringBuilder()

    // Game.platforms LIKE '%XONE%' OR Game.platforms LIKE '%PC%'

    for (platformIndex in platformIndices) {
        sb.append("platforms LIKE '%${allPlatforms[platformIndex].abbreviation}%'")
        sb.append(" OR ")
    }
    return sb.toString().removeSuffix(" OR ")
}




@Query("SELECT * FROM Game WHERE :likeClauses")
fun getGames(likeClauses: String): DataSource.Factory<Int, Game>

Вот еще одна вещь, которую я попробовал, но по какой-то причине это не сработало: Передача строки для использования в качестве части комнаты query

Я предполагаю, что RawQuery подойдет для этого? Есть ли другой способ?

Ответы [ 2 ]

1 голос
/ 06 марта 2020

Вы можете использовать @ RawQuery и строить SimpleSQLiteQuery динамически:

В дао:

@RawQuery(observedEntities = [Game::class])
fun getGames(query: SupportSQLiteQuery): DataSource.Factory<Int, Game>

Здесь buildFinalQuery функция:

fun buildFinalQuery(platforms: List<String>): SimpleSQLiteQuery {
    val selectQuery = "SELECT * FROM Game"

    val finalQuery = selectQuery + platforms.joinToString(prefix = " WHERE ", separator = " OR ") {
        "Game.platforms LIKE '%$it%'"
    }

    return SimpleSQLiteQuery(finalQuery)
}

val query = buildFinalQuery("SNES", "MAC", "PC")
dao.getGames(query)
0 голосов
/ 06 марта 2020

Я думаю, что ваше решение не работает, потому что Room автоматически экранирует сгенерированную строку для предотвращения SQL Injection.

Для решения вашей проблемы вы должны использовать оператор SQL -In.
Подробнее об операторе SQL -IN

Ваш DAO может выглядеть вот так

 @Query("SELECT * FROM Game WHERE platforms IN(:platformsToShow)")
 fun getGames(platformsToShow: Array<String>): DataSource.Factory<Int, Game>

Вот сообщение StackOverflow с тем же решением

ПРИМЕЧАНИЕ ЭТО РЕШЕНИЕ РАБОТАЕТ ТОЛЬКО С ТОЧНЫМИ РЕЗУЛЬТАТАМИ ПОИСКА
Для поддержки прописных и строчных букв вы можете использовать функцию SQL UPPER или LOWER.

SELECT * FROM Game
WHERE UPPER(platforms) IN ('AMI', 'SNES', 'PC');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...