【问题标题】:Generate sql query by anorm, with all nulls except one通过 anorm 生成 sql 查询,除一个之外的所有空值
【发布时间】:2015-07-08 18:06:51
【问题描述】:

我使用 play framework 2.3.8 和 scala 开发 Web 应用程序,后端和前端架构复杂。作为后端,我们使用 MS SQL,有许多存储过程,并通过 anorm 调用它。这是问题之一。

我需要更新数据库中的一些字段。前端调用play框架,接收字段名和值。然后我解析,字段名称,然后我需要为更新字段生成 SQL 查询。我需要为所有参数分配空值,除了接收参数。我尝试这样做:

def updateCensusPaperXX(name: String, value: String, user: User) = {
  DB.withConnection { implicit c =>
    try {
        var sqlstring = "Execute [ScXX].[updateCensusPaperXX] {login}, {domain}"
        val params = List(
          "fieldName1",
          "fieldName2",
          ...,
          "fieldNameXX"
        )
        for (p <- params){
          sqlstring += ", "
          if (name.endsWith(p))
            sqlstring += value
          else
            sqlstring += "null"

        }
        SQL(sqlstring)
          .on(
            "login" -> user.login,
            "domain" -> user.domain,
          ).execute()
    } catch {
      case e: Throwable => Logger.error("update CensusPaper04 error", e)
    }
  }
}

但实际上这并不适用于所有情况。例如,当我尝试保存字符串时,它会给我一个错误,例如:

com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near 'some phrase'

使用除一个以外的所有空值的异常生成 sql 查询的最佳方法是什么?

【问题讨论】:

  • 您只需使用Option.empty[ParamType] 传递一个JDBC NULL

标签: sql-server scala playframework playframework-2.3 anorm


【解决方案1】:

发生这种情况的原因是,当您将字符串值直接写入 SQL 语句时,它需要被引用。解决此问题的一种方法是确定哪些字段是字符串并添加条件逻辑以确定是否引用该值。这可能不是最好的方法。作为一般规则,您应该使用命名参数,而不是使用参数值构建字符串。这有几个好处:

  1. 您可能会更容易诊断问题,因为您会在运行时收到更合理的错误消息。
  2. 它可以防止 SQL 注入的可能性。
  3. 虽然在存储过程调用的情况下这可能不会带来太多好处,但您可以通过重用准备好的语句获得通常的性能优势。

这意味着您应该将字段列表视为命名参数,就像对待用户和域一样。这可以通过对上面的代码进行一些小的更改来完成。首先,您可以按如下方式构建 SQL 语句:

    val params = List(
      "fieldName1",
      "fieldName2",
      ...,
      "fieldNameXX"
    )

    val sqlString = "Execute [ScXX].[updateCensusPaperXX] {login}, {domain}," +
      params.map("{" + _ + "}").mkString{","}

上面发生的情况是您不需要直接插入值,因此您可以通过将参数列表添加到查询字符串的末尾来构建字符串。

然后您可以继续并开始构建您的参数列表。注意,SQLon 方法的参数是NamedParameter 的可变参数列表。基本上,我们需要创建包含“登录”、“域”和您正在填充的字段列表的 NamedParameters 序列。像下面这样的东西应该可以工作:

    val userDomainParams: Seq[NamedParameter] = (("login",user.login),("domain",user.domain))
    val additionalParams = params.map(p => 
      if (name.endsWith(p)) 
        NamedParameter(p, value)
      else 
        NamedParameter(p, None)
    ).toSeq
    val fullParams = userDomainParams ++ additionalParams
    // At this point you can execute as follows
    SQL(sqlString).on(fullParams:_*).execute()

这里发生的是您构建参数列表,然后使用 splat 运算符 :_* 将序列扩展为 on 方法所需的可变参数。注意上面NamedParameter中使用的None被Anorm转换成jdbc NULL

这解决了与字符串相关的问题,因为您不再将字符串直接写入查询中,并且它具有额外的好处,消除了与写入 SQL 字符串而不是使用参数相关的其他问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 2021-07-24
    • 2020-01-06
    • 1970-01-01
    • 2020-04-20
    • 2022-08-17
    相关资源
    最近更新 更多