2012-03-02 20 views
23

anormで句「の」使用する簡単な方法と思わない:怒りの中の "In"節?

val ids = List("111", "222", "333") 
val users = SQL("select * from users where id in ({ids})").on('ids-> ???).as(parser *) 

???部品を交換する方法は?

私が試した:

on('ids -> ids) 
on('ids -> ids.mkString("'","','","'")) 
on('ids -> ids.mkString("','") 

をしかし、どれも機能しません。私は議論の中で正確に同じ問題を参照してください

:これはあまりにも複雑になっている

val params = List(1, 2, 3) 

val paramsList = for (i <- 0 until params.size) yield ("userId" + i) 

// ---> results in List("userId0", "userId1", "userId2") 

User.find("id in ({%s})" 

    // produces "id in ({userId0},{userId1},{userId2})" 
    .format(paramsList.mkString("},{")) 

    // produces Map("userId0" -> 1, "userId1" -> 2, ...) 
    .on(paramsList.zip(params)) 
    .list() 

https://groups.google.com/d/topic/play-framework/qls6dhhdayc/discussionは、著者が複雑なソリューションを持っています。

もっと簡単な方法はありますか?または、それを簡単にするために何かを提供する必要がありますか?

答えて

-1
User.find("id in (%s)" 
    .format(params.map("'%s'".format(_)).mkString(",")) 
    .list() 
+3

この解決方法は、問合せ文字列に直接バインド(バインドを使用するのではなくエスケープなし)を貼り付けるため、SQLインジェクションに脆弱ですが、パラメーター。 14文字を節約する価値はありません! –

+1

セキュリティホールには14文字ほどの価値はありませんか? –

-1
val ids = List("111", "222", "333") 
val users = SQL("select * from users 
       where id in 
       (" + ids.reduceLeft((acc, s) => acc + "," + s) + ")").as(parser *) 
+3

'reduceLeft'部分を単に' ids.mkString( "、") 'と書くのはより慣用的です。また、他の答えと同様に、これはパラメータを直接クエリ文字列に入れるため、SQLインジェクションに対して脆弱です。 –

0

私は最近、同じ問題を抱えていました。残念なことに、文字列補間を使用せずにSQLインジェクションに脆弱な方法がないようです。それくぎ付け

val input = "1,2,3,4,5" 

// here there will be an exception if someone is trying to sql-inject you 
val list = (_ids.split(",") map Integer.parseInt).toList 

// re-create the "in" string 
SQL("select * from foo where foo.id in (%s)" format list.mkString(",")) 
8

:私は何をやってしまったことはちょっとint型とバックのリストにそれを変換することによって、それを消毒して

!このスレッドではこれ以上のアップデートはありませんでしたが、それでも関連性があるようです。そのために、そして答えがないので、私は考慮のために私のものを投げると思った。

Anormは 'IN'句をサポートしていません。私は彼らの意志を疑う。 Anormに「ORMのように」感じさせたので、彼らは特にそれらの句を取り出したポストを読むことさえできません。

ただし、IN句をサポートする短いクラスにSqlQueryをラップし、必要に応じてそのクラスをSqlQueryに変換するのは簡単です。

ここにコードを貼り付けるのではなく、ちょっと時間がかかるので、ここに私のブログへのリンクがあります。ここにコードを掲示しました。

In clause with Anorm

基本的に、あなたが私のブログからのコードを持っている場合、あなたの文は次のようになります。

RichSQL(""" SELECT * FROM users WHERE id IN ({userIds}) """).onList("userIds" -> userIds).toSQL.as(userParser *)(connection) 
0

多分それは手遅れだが、ここでも動作しますカスタム文字列の補間を使用するためのヒントです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 *) 

だから、文字列の補間を使用すると、それがより簡潔で読みやすくなります。

そして、IN句を使用した場合のために、あなたが書くことができます。

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:_*) 
    } 
    } 

} 
1

おそらく遅くなりますが、同じものを探している人にはこれを追加します。 これを克服するために、組み込みのデータベース機能を使用できます。これは、AnormがORMに対して持っている利点の1つです。たとえば、PostgreSQLを使用している場合、あなたのリストを配列として渡してクエリの配列をネストすることができます:

私はidsが整数であると仮定します。当初"Using multi-value parameter"

裏:

val ids = List(1, 2, 3) 

val idsPgArray = "{%s}".format(ids.mkString(",")) //Outputs {1, 2, 3} 

val users = SQL(
    """select * from users where id in (select unnest({idsPgArray}::integer[]))""" 
).on('ids-> ???).as(parser *) 

実行されたクエリは

select * from users where id in (1, 2, 3) 
12

に等しい

select * from users where id in (select unnest('{1, 2, 3}'::integer[])) 

はAnormは現在、このような場合をサポートする(およびそれ以上)2.3以降であろう例:

val ids = Seq("111", "222", "333") 
val users = SQL("select * from users where id in ({ids})").on('ids-> ids).as(parser *) 
+0

id($ ids) "。as(parser。*)'のように、 'SQL * select * – cchantep

関連する問題