How can I turn a list of strings into LIKE clauses in a Room Query?

ぐ巨炮叔叔 提交于 2020-03-25 16:04:26

问题


I have a table called games that has a column called platforms, which contains a list of platform abbreviations. This is a list of all the platforms that specific game came out on. Here's an example of one of the cells in platforms:

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

The user can choose any number of platforms they wish to view games for. For example, they may choose to see games for the following platforms:

SNES, MAC, PC

So I need a way to programmatically construct a Room query that would find games in the selected platforms. I need to somehow generate an arbitrary number of LIKE clauses and inject them into the query. I tried the following, but it returned no results:

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>

Here's another thing I tried, but it didn't work for some reason: Passing in a string to use as part of a Room query

I'm guessing RawQuery would work for this? Is there another way though?


回答1:


You can use @RawQuery and build SimpleSQLiteQuery dynamically:

In dao:

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

Here buildFinalQuery function:

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)



回答2:


I think your solution does not work because Room automatically escapes your generated string to prevent a SQL Injection.

To solve your problem you should use the SQL-In operator.
Read more about the SQL-IN operator

Your DAO could look like this

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

Here is a StackOverflow Post with the same solution

NOTE THIS SOLUTION ONLY WORKS WITH EXACT SEARCH RESULTS
To support upper and lower case you could use the SQL UPPER or LOWER function.

SELECT * FROM Game
WHERE UPPER(platforms) IN ('AMI', 'SNES', 'PC');


来源:https://stackoverflow.com/questions/60559869/how-can-i-turn-a-list-of-strings-into-like-clauses-in-a-room-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!