简体   繁体   English

使用Anorm RowParser

[英]Using Anorm RowParser

I have been using Play framework 2.0 for about 6 months, I have been wondering why they use so many boilerplate code to parse from my SQL query returns, like below: 我一直在使用Play Framework 2.0大约6个月,我一直想知道为什么它们使用这么多样板代码从我的SQL查询返回中进行解析,如下所示:

case class Journal_accountDetail(amount: Double, states: Boolean)

val Journal_AccountParser: RowParser[Journal_accountDetail] = {
    get[Double] ("amount") ~
    get[Boolean] ("states") map({
        case amount~states => Journal_accountDetail(amount,states)
    })
}

Is it something that boost Play framework performance ?? 它可以提高Play框架的性能吗?

The parsing API can seem a bit tedious at first, but it's quite powerful when you start combining and re-using the parsers, and much less ugly than pattern matching in every function that returns an SQL result. 最初,解析API似乎有点乏味,但是当您开始组合和重用解析器时,解析API会非常强大,并且比返回SQL结果的每个函数中的模式匹配丑陋得多。

Imagine something like this: 想象这样的事情:

case class User(id: Int, name: String, address: Address)
case class Address(id: Int, street: String, city: String, state: State, country: Country)
case class State(id: Int, abbrev: String, name: String)
case class Country(id: Int, code: String, name: String)

To construct the User you need to parse a result with multiple JOIN s. 要构造User您需要使用多个JOIN解析结果。 Rather than having one large parser, we construct one for each class in it's companion object: 我们没有一个大型的解析器,而是为它的伴随对象中的每个类构造了一个解析器:

object User {
    val parser: RowParser[User] = {
        get[Int]("users.id") ~
        get[String]("users.name") ~ 
        Address.parser map {
            case id~name~address => User(id, name, address)
        }
    }
}

object Address {
    val parser: RowParser[Address] = {
        get[Int]("address.id") ~
        get[String]("address.street) ~
        get[String]("address.city") ~ 
        State.parser ~
        Country.parser map {
            case id~street~city~state~country => Address(id, street, city, state, country)
        }
    }
}

object State {
    val parser: RowParser[State] = {
        get[Int]("states.id") ~
        get[String]("states.abbrev") ~ 
        get[String]("states.name") map {
            case id~abbrev~name => State(id, abbrev, name)
        }
    }
}

object Country {
    val parser: RowParser[Country] = {
        get[Int]("countries.id") ~
        get[String]("countries.code") ~ 
        get[String]("countries.name") map {
            case id~code~name => Country(id, code, name)
        }
    }
}

Note how I'm using the full table space in the parsers, in order to avoid column name collisions. 请注意我如何在解析器中使用完整的表空间,以避免列名冲突。

Altogether, this looks like a lot of code, but for each source file it's only a small footprint. 总的来说,这看起来像很多代码,但是对于每个源文件来说,它只占很小的空间。 And the largest benefit is that our User parser is quite clean despite it's complex structure. 最大的好处是尽管结构复杂,我们的User解析器还是很干净的。 Let's say in User the address is actually Option[Address] . 假设在Useraddress实际上是Option[Address] Then accounting for that change is as simple as changing Address.parser in the User parser to (Address.parser ?) . 然后,占这一变化是改变,因为简单Address.parserUser解析器(Address.parser ?)

For parsing simple queries, yes it does seem like a lot of boilerplate. 对于解析简单查询,是的,它看起来确实很简单。 But I'm quite thankful for the parsing API when it comes to parsing examples like the one above (and much more complex ones). 但是,对于解析上述示例(以及更复杂的示例)的解析API,我非常感激。

anorm.SqlParser also provides convinent parser functions, like .str , .int , .float , .double , ... instead of .get[String] , .get[Int] , .get[Float] , .get[Double] . anorm.SqlParser还提供了便捷的解析器功能,例如.str.int.float.double ,...而不是.get[String] .float .double .get[Int] .float .double .get[Float] .float .double .get[Double] Best regards. 最好的祝福。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM