簡體   English   中英

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

[英]Using the Parser API with nullable columns in Anorm 2.4

現在我已經升級到Anorm 2.4,我真的很難擺脫棄用警告。 我已經看過如何在Anorm中處理null但它對我沒有幫助。

我們舉一個簡單的例子: 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的Parser API

不確定這是否有幫助,但使用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

啊 - 忘了提到最后的'flatten'是因為我的解析器在這個例子中返回一個Option [Role],這取決於返回的行中是否存在所有必要的列值(這一位):

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.*)
    }
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM