在Anorm 2.4中使用具有可空列的Parser API

时间:2015-10-15 07:31:37

标签: scala playframework anorm

由于我升级到Anorm 2.4,我真的很难摆脱弃用警告。我看过How to handle null in Anorm,但这对我没有帮助。

我们举一个简单的例子:account数据库表:

  • id(bigint not null)
  • email_address(varchar not null)
  • first_name(varchar)
  • last_name(varchar)

我的Scala代码中可以有两个函数:getAccountOfIdgetAccountsOfLastName

  • getAccountOfId会返回0或1个帐户,因此Option[(Long, String, Option[String], Option[String])]会让我们的示例保持简单
  • getAccountsOfLastName会返回一个帐户列表(可能大小为0),因此List[(Long, String, Option[String], String)]可以让我们的示例更简单

这两个功能的部分代码:

def getAccountOfId(id: Long): Option[(Long, String, Option[String], Option[String])] = {
  DB.withConnection { implicit c =>
    val query = """select email_address, first_name, last_name
        from account
        where id = {id};"""

    /* Rest of the code that I struggle with unless I use deprecated functions */
  }
}

def getAccountsOfLastName(lastName: String): List[(Long, String, Option[String], String)] = {
  DB.withConnection { implicit c =>
    val query = """select id, email_address, first_name
        from account
        where last_name = {lastName};"""

    /* Rest of the code that I struggle with unless I use deprecated functions */
  }
}

我希望这两个函数中的“其余代码”基于Anorm's Parser API

2 个答案:

答案 0 :(得分:2)

不确定这是否有帮助,但是使用Anorm 2.4,我有一个类似于这样的案例类:

 final case class Role(id: Int,
                      label: String,
                      roletype: Int,
                      lid: Option[Int],
                      aid: Option[Int],
                      created: DateTime,
                      modified: DateTime)

然后只有它的解析器组合器,如下所示:

 val roleOptionRowParser = int("id") ~ str("label") ~ int("roletype") ~ (int("lid")?) ~ (int("vid")?) ~ get[DateTime]("created") ~
    get[DateTime]("modified") map {
    case id~label~roletype~lid~vid~created~modified ⇒ Some(Role(id, label, roletype, lid, vid, created, modified))
    case _ ⇒ None
}

所以你基本上只是解析使用?用于可选字段的组合器,然后根据从SQL结果行中提取的内容进行匹配。然后,您可以通过以下方式将其应用于查询:

SQL(s"""
            | select * from $source
            |    where $clause
            """.stripMargin).on(params : _*).as(rowParser.single).get

其中' rowParser'在这种情况下,它只是对最后一批代码中定义的roleOptionRowParser的引用。

如果您的查询返回了多行(或者希望有多行),那么您可以应用相同的组合器(例如?或*),然后再将它们传递给' as'功能如下:

SQL(s"""
            | select * from $source
            |    where $clause
            """.stripMargin).on(params : _*).as(rowParser *).flatten

SQL(s"""
            | select * from $source
            |    where $clause
            """.stripMargin).on(params : _*).as(rowParser ?).flatten
啊 - 忘了提及“平坦”'最后是因为我的解析器在此示例中返回一个Option [Role],具体取决于返回的行中是否存在所有必需的列值(此位):

case id~label~roletype~lid~vid~created~modified ⇒ Some(Role(id, label, roletype, lid, vid, created, modified))

因此,当返回多行时,我只是应用'展平'提升选项类型,以便我最终得到一个实际的'角色'实例。

干杯,

HTH。

答案 1 :(得分:0)

原来很简单:

formset = ArticleFormSet(request.POST)