Может быть, это слишком поздно, но вот подсказка для использования пользовательской строки интерполяции, которая также работает для решения проблемы предложения IN.
Я применил вспомогательный класс для определения интерполяции строк. Вы можете видеть это ниже, и вы можете просто скопировать и вставить, но сначала давайте посмотрим, как вы можете его использовать.
Вместо написать что-то
SQL("select * from car where brand = {brand} and color = {color} and year = {year} order by name").on("brand" -> brand, "color" -> color, "year" -> year).as(Car.simple *)
Вы можете просто написать:
SQL"select * from car where brand = $brand and color = $color and year = $year order by name".as(Car.simple *)
Таким образом, используя интерполяцию строки это более кратким и легким для чтения.
И в случае с помощью предложения, вы можете написать:
val carIds = List(1, 3, 5)
SQLin"select * from car where id in ($carIds)".as(Car.simple *)
Или для примера:
val ids = List("111", "222", "333")
val users = SQLin"select * from users where id in ($ids)".as(parser *)
Для получения дополнительной информации об интерполяции строк, проверить это link
Код для этого неявного класса:
package utils
object AnormHelpers {
def wild (str: String) = "%" + str + "%"
implicit class AnormHelper (val sc: StringContext) extends AnyVal {
// SQL raw -> it simply create an anorm.Sql using string interpolation
def SQLr (args: Any*) = {
// Matches every argument to an arbitrary name -> ("p0", value0), ("p1", value1), ...
val params = args.zipWithIndex.map(p => ("p"+p._2, p._1))
// Regenerates the original query substituting each argument by its name with the brackets -> "select * from user where id = {p0}"
val query = (sc.parts zip params).map{ case (s, p) => s + "{"+p._1+"}" }.mkString("") + sc.parts.last
// Creates the anorm.Sql
anorm.SQL(query).on(params.map(p => (p._1, anorm.toParameterValue(p._2))) :_*)
}
// SQL -> similar to SQLr but trimming any string value
def SQL (args: Any*) = {
val params = args.zipWithIndex.map {
case (arg: String, index) => ("p"+index, arg.trim.replaceAll("\\s{2,}", " "))
case (arg, index) => ("p"+index, arg)
}
val query = (sc.parts zip params).map { case (s, p) => s + "{"+ p._1 + "}" }.mkString("") + sc.parts.last
anorm.SQL(query).on(params.map(p => (p._1, anorm.toParameterValue(p._2))) :_*)
}
// SQL in clause -> similar to SQL but expanding Seq[Any] values separated by commas
def SQLin (args: Any*) = {
// Matches every argument to an arbitrary name -> ("p0", value0), ("p1", value1), ...
val params = args.zipWithIndex.map {
case (arg: String, index) => ("p"+index, arg.trim.replaceAll("\\s{2,}", " "))
case (arg, index) => ("p"+index, arg)
}
// Expands the Seq[Any] values with their names -> ("p0", v0), ("p1_0", v1_item0), ("p1_1", v1_item1), ...
val onParams = params.flatMap {
case (name, values: Seq[Any]) => values.zipWithIndex.map(v => (name+"_"+v._2, anorm.toParameterValue(v._1)))
case (name, value) => List((name, anorm.toParameterValue(value)))
}
// Regenerates the original query substituting each argument by its name expanding Seq[Any] values separated by commas
val query = (sc.parts zip params).map {
case (s, (name, values: Seq[Any])) => s + values.indices.map(name+"_"+_).mkString("{", "},{", "}")
case (s, (name, value)) => s + "{"+name+"}"
}.mkString("") + sc.parts.last
// Creates the anorm.Sql
anorm.SQL(query).on(onParams:_*)
}
}
}
Это решение фактически совпадает с предложенным в вопросе, за тем исключением, что оно уязвимо для SQL-инъекции, потому что вы вставляете параметры непосредственно в строку запроса (без экранирования!), Вместо того, чтобы использовать bind параметры. Не стоит этого ради спасения 14 персонажей! –
Разрывная дыра безопасности не стоит 14 символов ?! –