异常字符串插值不替换变量

Anorm String Interpolation not replacing variables

我们正在使用 Scala Play,我正在努力确保所有 SQL 查询都在使用 Anorm 的字符串插值。它适用于某些查询,但许多查询实际上并没有在执行查询之前替换变量。

import anorm.SQL
import anorm.SqlStringInterpolation

object SecureFile 
{
  val table = "secure_file"
  val pk = "secure_file_idx"
  ...

// This method works exactly as I would hope
def insert(secureFile: SecureFile): Option[Long] = {
  DBExec { implicit connection =>
    SQL"""
      INSERT INTO secure_file (
        subscriber_idx,
        mime_type,
        file_size_bytes,
        portal_msg_idx
      ) VALUES (
        ${secureFile.subscriberIdx},
        ${secureFile.mimeType},
        ${secureFile.fileSizeBytes},
        ${secureFile.portalMsgIdx}
        )
      """ executeInsert()
    }
  }

def delete(secureFileIdx: Long): Int = {
  DBExec { implicit connection =>
    // Prints correct values
    println(s"table: ${table} pk: ${pk} secureFileIdx: ${secureFileIdx} ")

    // Does not work
    SQL""" 
      DELETE FROM $table WHERE ${pk} = ${secureFileIdx} 
    """.executeUpdate()

    // Works, but unsafe
    val query = s"DELETE FROM ${table} WHERE ${pk} = ${secureFileIdx}" 
    SQL(query).executeUpdate() 
  }
}
....
}

在 PostgreSQL 日志中,很明显 delete 语句没有获取正确的值:

2015-01-09 17:23:03 MST ERROR:  syntax error at or near "" at character 23
2015-01-09 17:23:03 MST STATEMENT: DELETE FROM  WHERE  = 
2015-01-09 17:23:03 MST LOG:  execute S_1: ROLLBACK

我已经尝试了 execute、executeUpdate 和 executeQuery 的许多变体,结果相似。目前,我们正在使用基本的字符串替换,但这当然很糟糕,因为它没有使用 PreparedStatements。

Anorm 字符串插值被引入以传递参数(例如 SQL"Select * From Test Where id = $x),插值参数(例如 $x)根据适当的类型转换在基础 PreparedStament 上设置(参见上的用例https://www.playframework.com/documentation/2.3.x/ScalaAnorm).

下一个 Anorm 版本也将有 #$foo 语法来混合参数插值和标准字符串插值。这将允许编写 DELETE FROM #$table WHERE #${pk} = ${secureFileIdx} 并将其作为 DELETE FROM foo WHERE bar = ? 执行(如果文字 table"foo" 并且 pk"bar"),使用文字secureFileIdx 作为参数传递。见相关 pull request.

在发布下一个修订版之前,您可以从其主源构建 Anorm,并从中受益。

对于坐在这个页面上挠头并想知道他们可能遗漏了什么的其他人......

SQL("select * from mytable where id = $id") 

不同
SQL"select * from mytable where id = $id" 

前者不做字符串插值,后者做。

这在上述文档中很容易被忽视,因为提供的所有样本恰好有一个(不相关的)右括号(就像这句话一样)