如何使用Play和Anorm实现关系

时间:2018-02-08 16:52:10

标签: scala anorm

我目前正在使用Scala与Play Framework和Anorm来访问我的数据库。我一直是一名Ruby开发人员,仍然需要习惯像Play使用的依赖注入这样的新概念。

我将用一个简化的例子来说明我的问题。

目前,我的模型和持久性结构如下:

User.scala:

src

UserRepository.scala:

http://mydeployedsite.com/nonexistentpic.jpg

现在我必须添加另一个与用户相关的模型。我们来说评论。但是我仍然在努力如何在仍然使用依赖注入的同时最优雅地添加关系。

向User类添加一个方法听起来很糟糕,因为我总是需要在我调用该方法时注入一个持久性对象:

case class User (
  val id: Long
  val name: String
)

object User (
  val idColumn = "id"
  val nameColumn = "name"
)

我提出的下一个解决方案远非理想:

sealed trait UserRepository {
  def findAll: List[User]
}

class DatabaseUserRepository @Inject() (db: Database) extends UserRepository {
  val parser: RowParser[User] = Macro.parser[User](
    User.idColumn,
    User.nameColumn
  )

  def findById(id: Long): List[User] = {
    db.withConnection { implicit c =>
      SQL(
        """
          SELECT * FROM users;
        """
      ).as(parser.*)
    }
  }
}

这样我总是会收到评论,而不是在我需要的时候。通常使用空case class User ( ... ) { def comments(repo: CommentRepository): List[Comment] = { repo.findByUserId(this.id) } } 列表然后填写它的想法感觉不对。

在保留不可变状态和依赖注入的同时构建模型之间的关系怎么样?在任何地方都有一些例子吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

您可以在用户对象中创建注释选项:

case class User(id: Long, name: String, comments: Option[Seq[Comments]])

然后从查询中构建对象:

def findById(id: Long): List[User] = {
    val users = db.withConnection { implicit c =>
      SQL("SELECT u.id, u.name, c.comment FROM users as u 
           join Comments as c on u.id = c.id 
           where u.id = {uid}")
          .on('uid -> id)
          .as(parser.*)
    }

然后,您可以了解如何让RowParser创建一个没有评论的None

查看Anorm Row Parser API获取一些灵感