使用案例类/伴随对象模式时的 Scala 依赖注入(inject)

标签 scala playframework dependency-injection playframework-2.5

在迁移到 Play 2.5 时,我采用了依赖注入(inject)设计模式,包括 (JDBC) 数据库访问。

在类里面,我理解这个概念:

class Users @Inject() (db: Database)

但是我还没有看到当您需要在案例类和伴随对象模式的方法中访问数据库时如何应用它的讨论。基本模型示例为:

package models

import anorm._
import anorm.SqlParser._
import javax.inject._

import play.api.db._
import play.api.libs.functional.syntax._
import play.api.libs.json._


case class User @Inject() (db: Database) (
    id: Option[Long] = None,
    email: String
) {
    def save = {
        id.map { id => User.findById(id) } match {
            case None => create
            case _ => update
        }
    }

    def create = db.withConnection { implicit conn =>
        SQL(
            """INSERT INTO users (email) VALUES ({email})"""
        ).on(
            'email -> email
        ).executeUpdate()

        this
    }

    def update = ...
}

object User {    
    val simple = {
        get[Option[Long]]("id") ~
        get[String]("email") map {
            case id ~ email =>
                User(id, email)
        }
    }

    def findById(id: Long) = db.withConnection { implicit conn =>
        SQL("""SELECT * FROM users WHERE id = {id}""").on('id -> id).as(User.simple.singleOpt)
    }
}

这会更改案例类的签名(使其在 val simple = { ... } 内不可用),并且我无法弄清楚如何注入(inject)/访问伴随对象中的数据库。尝试@Inject() var db: Database _对象内会导致 NullPointerExceptions 的世界,我想避免这种情况。

在依赖注入(inject)的世界中,对于这种常见用例的推荐设计模式是什么?

最佳答案

一种常见的模式是将数据库功能放在单独的类中。在您的情况下,仅将数据留给用户:

 case class User(id: Option[Long] = None, email: String)

并将数据库功能放入一个单独的类中:

class UserRepository @Inject()(db: Database) {
    def save(user: User) = { ... }
    def create() : User = { ... }
    def findById(id: Long) : Option[User] = { ... }
}

不知道如何在代码中使用 User 对象。但是使用这种模式,您不会携带对数据库的引用,每个用户对象基本上都会将持久性实现泄漏到使用用户对象的任何地方。也许您想要这个,但是您在 val simple = ... 中创建 User 对象的方式向我表明您想要创建仅包含数据的用户对象。

现在您正在传递用户对象,并且仅当需要数据库功能时才注入(inject)UserRepository

这并不能完全回答您有关将依赖项注入(inject)伴生对象的问题,但无论如何可能会有所帮助。

关于使用案例类/伴随对象模式时的 Scala 依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40029187/

相关文章:

scala - 如何使用 scala 将 postgreSQL 数据库连接到 Apache Spark?

scala - 有没有一种简单的方法可以将 Option[Task[T]] 转换为 Task[Option[T]]?

android - Eclipse、Android、Scala 变得简单但仍然无法正常工作

scala - 带有 Play Scala 的 ReactiveMongo

playframework - 在scala模板中使用$符号?

组件、服务等之外的 Angular 2 服务注入(inject)

java - 动态创建对象的依赖注入(inject)的好处

scala - 如何在 Actor 的接收方法中使用 Future 来处理容错?

c# - 如何使用具有 "greedy"构造函数的 Scan 将 StructureMap 与通用未封闭类型一起使用

playframework - 强制 Play Framework 依赖