如何将字符串列表转换为房间查询中的 LIKE 子句?
How can I turn a list of strings into LIKE clauses in a Room Query?
我有一个名为 games
的 table,它有一个名为 platforms
的列,其中包含一个平台缩写列表。这是特定游戏出现的所有平台的列表。这是 platforms
中的一个单元格的示例:
AMI,GG,SNES,CPC,AST,C64,SPEC,MAC,PS2,NES,3DO,ARC,XBGS,PS3N,PC,IPHN,DSI,HALC,PSPN,ANDR,
用户可以选择他们希望查看游戏的任意数量的平台。例如,他们可能会选择查看以下平台的游戏:
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>
这是我尝试过的另一件事,但由于某种原因没有奏效:
Passing in a string to use as part of a Room query
我猜 RawQuery 是否适用于此?还有其他方法吗?
您可以动态使用@RawQuery and build 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)
我认为您的解决方案不起作用,因为 Room 会自动转义您生成的字符串以防止 SQL 注入。
要解决您的问题,您应该使用 SQL-In 运算符。
Read more about the SQL-IN operator
你的 DAO 可能看起来像这样
@Query("SELECT * FROM Game WHERE platforms IN(:platformsToShow)")
fun getGames(platformsToShow: Array<String>): DataSource.Factory<Int, Game>
请注意,此解决方案仅适用于精确的搜索结果
要支持大写和小写,您可以使用 SQL UPPER
或 LOWER
函数。
SELECT * FROM Game
WHERE UPPER(platforms) IN ('AMI', 'SNES', 'PC');
我有一个名为 games
的 table,它有一个名为 platforms
的列,其中包含一个平台缩写列表。这是特定游戏出现的所有平台的列表。这是 platforms
中的一个单元格的示例:
AMI,GG,SNES,CPC,AST,C64,SPEC,MAC,PS2,NES,3DO,ARC,XBGS,PS3N,PC,IPHN,DSI,HALC,PSPN,ANDR,
用户可以选择他们希望查看游戏的任意数量的平台。例如,他们可能会选择查看以下平台的游戏:
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>
这是我尝试过的另一件事,但由于某种原因没有奏效: Passing in a string to use as part of a Room query
我猜 RawQuery 是否适用于此?还有其他方法吗?
您可以动态使用@RawQuery and build 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)
我认为您的解决方案不起作用,因为 Room 会自动转义您生成的字符串以防止 SQL 注入。
要解决您的问题,您应该使用 SQL-In 运算符。
Read more about the SQL-IN operator
你的 DAO 可能看起来像这样
@Query("SELECT * FROM Game WHERE platforms IN(:platformsToShow)")
fun getGames(platformsToShow: Array<String>): DataSource.Factory<Int, Game>
请注意,此解决方案仅适用于精确的搜索结果
要支持大写和小写,您可以使用 SQL UPPER
或 LOWER
函数。
SELECT * FROM Game
WHERE UPPER(platforms) IN ('AMI', 'SNES', 'PC');