代码之家  ›  专栏  ›  技术社区  ›  Will Croft

使用case类/伴随对象模式时的Scala依赖注入

  •  7
  • Will Croft  · 技术社区  · 8 年前

    在课堂上,我理解以下概念:

    class Users @Inject() (db: Database)
    

    但我还没有看到关于当您需要在case类和伴随对象模式的方法中进行数据库访问时,这可能如何应用的讨论。示例基本模型是:

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

    这将更改case类的签名(使其在 val simple = { ... } @Inject() var db: Database _ 在对象中,会产生我希望避免的空指针异常。

    在依赖注入的世界中,这个常见用例的推荐设计模式是什么?

    1 回复  |  直到 8 年前
        1
  •  7
  •   Josef    8 年前

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

     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 = ... 指示您要创建仅包含数据的用户对象。

    现在,您正在传递用户对象,只有在需要数据库功能时,才注入 UserRepository .

    这并不能确切地回答您关于将依赖注入到同伴对象中的问题,但无论如何可能会有所帮助。