简体   繁体   English

如何使用 Play 和 Anorm 实现关系

[英]How to implement relations using Play and Anorm

I'm currently using Scala with the Play Framework and Anorm to access my database.我目前正在使用 Scala 和 Play Framework 和 Anorm 来访问我的数据库。 I've been mostly a Ruby developer and still have to get used to the new concepts like dependency injection which Play uses out of the box.我主要是一名 Ruby 开发人员,但仍然必须习惯 Play 开箱即用的依赖注入等新概念。

I'll use a simplified example to show my problem.我将使用一个简化的示例来说明我的问题。

Currently I have my models and persistency structured like this:目前我的模型和持久性结构如下:

User.scala:用户.scala:

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

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

UserRepository.scala: UserRepository.scala:

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

Now I have to add another model which is related to users.现在我必须添加另一个与用户相关的模型。 Let's say comments.说说评论吧。 But I struggle how to add the relation most elegantly while still using Dependency Injection.但是我很难在仍然使用依赖注入的同时如何最优雅地添加关系。

Adding a method to the User class sounds horrible because I would always have to have an injected persistency object at the point where I call the method:向 User 类添加方法听起来很糟糕,因为我总是必须在调用该方法的地方注入一个持久性对象:

case class User (
  ...
) {
  def comments(repo: CommentRepository): List[Comment] = {
    repo.findByUserId(this.id)
  }
}

The next solution I came up with is as well far from ideal:我想出的下一个解决方案也远非理想:

case class User (
  ...
) {
  var comments: List[Comment] = List()
}

class DatabaseUserRepository @Inject() (db: Database, commentRepo: CommentRepository) extends UserRepository {
  ...
  def findById(id: Long): List[User] = {
    val users = db.withConnection { implicit c =>
      SQL(
        """
          SELECT * FROM users;
        """
      ).as(parser.*)
    }

    users.map { u => u.comments = commentRepo.findByUserId(u.id) }
  }
}

This way I would always fetch the comments and not when I need them AND generally the idea of using an empty var comments list and later filling it feels wrong.这样我总是会获取评论,而不是在我需要它们的时候,而且通常使用空的var comments列表然后填充它的想法是错误的。

How would it look like to structure relations between models while preserving immutable state and dependency injection?在保持不可变状态和依赖注入的同时构建模型之间的关系会是什么样子? Are there some examples anywhere?任何地方都有一些例子吗?

Thanks!谢谢!

You can create an option of comments in the user object:您可以在用户对象中创建一个评论选项:

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

Then build the object from your query:然后从您的查询构建对象:

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

You can then work out how to get a RowParser to create a None where no comments exist.然后,您可以找出如何获取RowParser以在不存在注释的RowParser下创建None

Have a look at Anorm Row Parser API for some inspiration看看Anorm Row Parser API以获得一些灵感

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

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