我目前正在使用Scala与Play Framework和Anorm来访问我的数据库。我一直是一名Ruby开发人员,仍然需要习惯像Play使用的依赖注入这样的新概念。
我将使用一个简化的例子来说明我的问题。
目前我的模型和持久性结构如下:
User.scala:
case class User (
val id: Long
val name: String
)
object User (
val idColumn = "id"
val nameColumn = "name"
)
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.*)
}
}
}
现在我必须添加另一个与用户相关的模型。我们来说评论。但是我仍然在努力如何在仍然使用依赖注入的同时最优雅地添加关系。
向User类添加方法听起来很糟糕,因为我总是必须在我调用方法时注入一个持久性对象:
case class User (
...
) {
def comments(repo: CommentRepository): List[Comment] = {
repo.findByUserId(this.id)
}
}
我想出的下一个解决方案远非理想:
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) }
}
}
这样我总是会获取注释,而不是当我需要它们时,通常使用空的var comments
列表然后填充它的想法感觉不对。
在保留不可变状态和依赖注入的同时,如何构建模型之间的关系?在哪里有一些例子吗?
谢谢!
您可以在用户对象中创建注释选项:
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的灵感