在 Anorm 2.4 中将解析器 API 与可为空的列一起使用
Using the Parser API with nullable columns in Anorm 2.4
既然我已经升级到 Anorm 2.4,我真的很难摆脱弃用警告。我看过 How to handle null in Anorm,但对我的帮助还不够。
举个简单的例子:account
数据库table:
id
(bigint 不为空)
email_address
(varchar 不为空)
first_name
(varchar)
last_name
(varchar)
我的 Scala 代码中可以有 2 个函数:getAccountOfId
和 getAccountsOfLastName
。
getAccountOfId
returns 0 或 1 个帐户,因此 Option[(Long, String, Option[String], Option[String])]
使我们的示例保持简单
getAccountsOfLastName
returns 一个帐户列表(其大小可能为 0),因此 List[(Long, String, Option[String], String)]
使我们的示例保持简单
这2个函数的部分代码:
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 */
}
}
我希望这两个函数中的"rest of the code"基于Anorm's Parser API。
不确定这是否有帮助,但使用 Anorm 2.4,我有一个案例 class 看起来像这样:
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
啊 - 忘了提到最后的 'flatten' 因为我的解析器在这个例子中 returns 一个选项[角色],取决于所有必要的列值是否存在返回的行(这个位):
case id~label~roletype~lid~vid~created~modified ⇒ Some(Role(id, label, roletype, lid, vid, created, modified))
因此,当返回多行时,我只是应用 'flatten' 来提升 Option 类型,这样我最终得到一个实际 'Role' 实例的列表。
干杯,
HTH.
事实证明这很简单:
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};"""
val rowParser = str("email_address") ~ (str("first_name") ?) ~ (str("last_name") ?) map {
case emailAddress ~ firstNameOpt ~ lastNameOpt => (id, emailAddress, firstNameOpt, lastNameOpt)
}
SQL(query).on("id" -> id).as(rowParser.singleOpt)
}
}
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};"""
val rowParser = long("id") ~ str("email_address") ~ (str("first_name") ?) map {
case id ~ emailAddress ~ firstNameOpt => (id, emailAddress, firstNameOpt, lastName)
}
SQL(query).on("lastName" -> lastName).as(rowParser.*)
}
}
既然我已经升级到 Anorm 2.4,我真的很难摆脱弃用警告。我看过 How to handle null in Anorm,但对我的帮助还不够。
举个简单的例子:account
数据库table:
id
(bigint 不为空)email_address
(varchar 不为空)first_name
(varchar)last_name
(varchar)
我的 Scala 代码中可以有 2 个函数:getAccountOfId
和 getAccountsOfLastName
。
getAccountOfId
returns 0 或 1 个帐户,因此Option[(Long, String, Option[String], Option[String])]
使我们的示例保持简单getAccountsOfLastName
returns 一个帐户列表(其大小可能为 0),因此List[(Long, String, Option[String], String)]
使我们的示例保持简单
这2个函数的部分代码:
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 */
}
}
我希望这两个函数中的"rest of the code"基于Anorm's Parser API。
不确定这是否有帮助,但使用 Anorm 2.4,我有一个案例 class 看起来像这样:
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
啊 - 忘了提到最后的 'flatten' 因为我的解析器在这个例子中 returns 一个选项[角色],取决于所有必要的列值是否存在返回的行(这个位):
case id~label~roletype~lid~vid~created~modified ⇒ Some(Role(id, label, roletype, lid, vid, created, modified))
因此,当返回多行时,我只是应用 'flatten' 来提升 Option 类型,这样我最终得到一个实际 'Role' 实例的列表。
干杯,
HTH.
事实证明这很简单:
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};"""
val rowParser = str("email_address") ~ (str("first_name") ?) ~ (str("last_name") ?) map {
case emailAddress ~ firstNameOpt ~ lastNameOpt => (id, emailAddress, firstNameOpt, lastNameOpt)
}
SQL(query).on("id" -> id).as(rowParser.singleOpt)
}
}
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};"""
val rowParser = long("id") ~ str("email_address") ~ (str("first_name") ?) map {
case id ~ emailAddress ~ firstNameOpt => (id, emailAddress, firstNameOpt, lastName)
}
SQL(query).on("lastName" -> lastName).as(rowParser.*)
}
}