关于sql server:通过anorm生成sql查询,除一个以外的所有null

Generate sql query by anorm, with all nulls except one

我使用play框架2.3.8和scala开发Web应用程序,后端和前端均具有复杂的体系结构。作为后端,我们使用MS SQL和许多存储过程,并由anorm对其进行了调用。这是问题之一。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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)
    }
  }
}

但是实际上并非在所有情况下都有效。例如,当我尝试保存字符串时,它给我一个错误,例如:

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

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


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

  • 诊断问题可能会更容易,因为在运行时您将收到更明智的错误消息。
  • 它可以防止SQL注入的可能性。
  • 您可以获得重用已准备好的语句的通常的性能好处,尽管在存储过程调用的情况下这可能不算什么。
  • 这意味着您应该像对待用户和域一样将字段列表视为命名参数。这可以通过对上面的代码进行一些小的更改来完成。首先,您可以按照以下方式构建SQL语句:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        val params = List(
         "fieldName1",
         "fieldName2",
          ...,
         "fieldNameXX"
        )

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

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

    然后您可以继续并开始构建参数列表。注意,SQLon方法的参数是NamedParameter的变量列表。基本上,我们需要创建NamedParameters的Seq,以覆盖" login"," domain"和要填充的字段列表。像下面这样的东西应该起作用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        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方法的参数所需的varargs。请注意,上面的NamedParameter中使用的None由Anorm转换为jdbc NULL

    这可以解决与字符串有关的问题,因为您不再需要将字符串直接写入查询中,并且具有消除与编写SQL字符串而不是使用参数有关的其他问题的更多好处。