Może to zbyt późno, ale tutaj jest to wskazówka dla użyciu niestandardowego interpolacji ciąg, który również działa do rozwiązania problemu klauzuli IN.
Zaimplementowałem klasę pomocniczą do zdefiniowania interpolacji ciągów znaków. Możesz to zobaczyć poniżej i możesz po prostu skopiować i wkleić, ale najpierw zobaczmy, jak możesz z niego korzystać.
Zamiast napisać coś
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 *)
można po prostu napisać:
SQL"select * from car where brand = $brand and color = $color and year = $year order by name".as(Car.simple *)
Więc za pomocą interpolacji ciąg jest bardziej zwięzły i łatwiejsze do odczytania.
, aw przypadku korzystania z klauzuli, można napisać:
val carIds = List(1, 3, 5)
SQLin"select * from car where id in ($carIds)".as(Car.simple *)
Albo dla przykładu:
val ids = List("111", "222", "333")
val users = SQLin"select * from users where id in ($ids)".as(parser *)
Aby uzyskać więcej informacji na temat interpolacji smyczkowy, zaznacz to link
Kod tej niejawnej klasy jest następujący:
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:_*)
}
}
}
To rozwiązanie jest skutecznie takie samo, jak sugerowane w pytaniu, z jednym wyjątkiem, że jest podatne na iniekcję SQL, ponieważ wklejasz parametry bezpośrednio do ciągu zapytania (bez ucieczki!), Zamiast używać wiązania parametry. Nie warto, aby zaoszczędzić 14 znaków! –
Otwarta luka w zabezpieczeniach nie jest warta 14 znaków ?! –