3

在迁移到Play 2.5时,我采用了依赖注入设计模式,包括用于(JDBC)数据库访问。使用case class/companion对象模式时的Scala依赖注入

在一流水平,我理解这个概念:

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() var db: Database _会导致我想避免的NullPointerException的世界。

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

+4

案例类并不意味着封装这样的“服务”功能,而DI也不是用于与对象一起工作 – cchantep

回答

6

一种常见的模式是将数据库功能放入单独的类中。你的情况只留下数据与用户:

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对象表明我想要创建包含数据的用户对象。

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

这不完全提供了有关依赖注入到伴随对象的问题的答案,但无论如何可能有帮助。

+0

谢谢!这是一个很好的模式 - 我应该也提到我正在从“Learning Play!Framework 2”书籍的以前的Play <2.5实现中工作:https://github.com/andypetrella/play2-book-chapters/blob/ master/chap4/play-sbook/app/models/User.scala –

+0

我打算继续并将其标记为已接受的答案,因为我认为这是对预期问题最接近的重构。看起来上面这本书提出的模式并不是最实用的模式。 –