【问题标题】:Scala - How to parse many-one relationships?Scala - 如何解析多一关系?
【发布时间】:2018-02-27 02:00:58
【问题描述】:

架构

我有两张桌子,比如teams 和players。其中,players 表中的每一行都有一个引用 teams 表的 team_id 外键。

我想要的结果是一个 JSON 数组,其中每个元素都是一个团队。该团队有一个players_info 键,它汇总了有关球员的一些信息,然后拥有所有球员的数组。基本上,我希望它看起来像以下

[
{
    "id": "Arsenal FC",
    "city": "London",
    "stadium_capacity": 60000,
    ....
    "players_info": {
        "count": 34,
        "average_price": 34,
        "players": [
            {
                "name": "Ozil",
                "price": 50,
                ....
            },
            {
                "name": "Wilshere",
                "price": 40,
                ....
            },
            .....   
        ]
},
{
    "id": "Chelsea FC",
    "city": "London",
    "stadium_capacity": 40000,
    ....
    "players_info": {
        "count": 39,
        "average_price": 54,
        "players": [
            {
                "name": "Hazard",
                "price": 60,
                ....
            },
            {
                "name": "Kante",
                "price": 45,
                ....
            },
            .....   
        ]
},
.....
 ]

问题

这是我目前所拥有的

case class Team(
    id: Int,
    name: String,
    ....
    players_info: JsValue
)

object Team {
    val parse = {

        ------- What do I do here? -------

        get[Int]("id") ~
        get[String]("name") ~
        .....
        get[String]("player_name") ~
        get[String]("player_price") map {
            case id ~ name ~ player_name ~ player_price ~ ... => Team(id, name, ???)
        }

    }
}

val teams = DB.withConnection {
  implicit connection =>
    SQL("SELECT * FROM teams JOIN players ON players.team_id = teams.id").as(Team.parse *)
}
val response = Json.toJson(teams)

我需要以下方面的帮助

  1. 如何在解析器中构造player_info JsValue,以便可以使用我的应用程序代码计算average_price 之类的内容,然后在一切准备就绪后初始化我的Team 类?
  2. 我不确定我处理此问题的整体架构是否正确。我也可以对此提出一些想法吗?
  3. 在解析和构造 JSON 的概念之后,我觉得我缺少一些整体上下文。我知道在哪里做这些事情很容易,但我不知道如何在 Scala 中做同样的事情。您能否指出一些相关的资源/教程,我可以在其中进行自我教育?

【问题讨论】:

    标签: scala parsing playframework


    【解决方案1】:

    就我个人而言,我会创建案例类,作为我将服务的 JSON 的 API 表示。

    case class ApiTeam(
        id: Int,
        name: String,
        ....
        players_info: ApiPlayersInfo
    )
    
    case class ApiPlayersInfo(
        ...
    )
    

    然后我会使用 Play JSON 来generate decoders/encoders with macros。

    import play.api.libs.json._
    implicit val playersInfoFormat = Json.format[ApiPlayersInfo]
    implicit val teamFormar = Json.format[ApiTeam]
    

    所以我不会手动解析它,而是让 Play JSON 为我处理它。然后我将只导入生成的隐式和

    val teamJson = Json.toJson(apiTeam)
    

    至于 Team 和 PlayersInfo 的内容,因为我只是构建普通对象,所以我可以使用 Scala 拥有的所有工具。因此,您基本上可以通过查询数据库进行计算,使用结果构建 Team 对象,然后将其转换为 JSON。

    case class Team(
        id: Int,
        name: String,
        ....
    )
    
    case class PlayersInfo(...)
    

    通过将任务分成更小的块,将更容易理解和维护。

    for {
      team <- DB.withConnection { implicit connection =>
        SQL("SELECT * FROM teams JOIN players ON players.team_id = teams.id").as(Team)
      }
      playersInfo <- DB.withConnection { implicit connection =>
        SQL("...").as(PlayersInfo)
      }
    } yield {
      val apiTeam = ApiTeam(...)
      Json.toJson(apiTeam)
    }
    

    您的问题是 Rails 教给您统一表示的不良做法:JSON、读取模型、写入模型和数据库行使用相同的类。它仅在您编写最基本的 CRUD 时才起作用,即使这样,当您遇到创建新实体的问题时它也会中断(视频:很多问题:如何在行创建期间处理丢失的 ID?)。在这里,您在数据库中有 2 个表,但希望将它们表示为聚合结果的一个 JSON。保持简单的最小情况是团队模型、玩家模型和聚合结果的单独模型。

    您越早开始对不同事物使用不同的表示,您就越早使其可维护和灵活。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-26
      • 1970-01-01
      • 2014-06-09
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多