PlayFramework:如何注入数据库对象

时间:2017-01-02 18:26:40

标签: scala playframework

我使用anorm进行播放框架,我有以下服务类:

@javax.inject.Singleton
class ProductService @Inject() (dbApi: DBApi) {

  private val DB = dbApi.database("default")

  def save(product: Product) = {
    DB.withConnection { implicit connection =>
      ....
    }
  }
}

这里有两个问题:

1)我不希望在每个Service类中添加行private val DB = dbApi.database("default")。抽象这个的最佳方法是什么?

2)我还希望数据源可配置,以便在编写集成测试时可以传递测试数据源

测试类:

import models.ProductService
import org.scalatestplus.play.{OneAppPerSuite, PlaySpec}
import play.api.db.Databases

class ProductSpec extends PlaySpec with OneAppPerSuite {

  var productService: ProductService = app.injector.instanceOf(classOf[ProductService])

  Databases.withDatabase(
    driver = "com.mysql.jdbc.Driver",
    url = "jdbc:mysql://localhost/playtest",
    config = Map(
      "user" -> "test",
      "password" -> "demo"
    )
  ) { database =>
    import play.api.db.evolutions._
    Evolutions.applyEvolutions(database)

    "Product" should {
      "be retrieved by Id" in {
        val product = productService.get(23)
        product.get.name must equal("mobile")
      }
    }
  }

}

有什么建议吗?

1 个答案:

答案 0 :(得分:2)

您可以注入database对象本身而不是DBApi。顺便说一句,Guice的最佳实践之一是inject only direct dependencies。所以,你的例子可能是这样的:

import play.api.db.Database

@Singleton
class ProductService @Inject() (database: Database) {

  def save(product: Product) = {
    database.withConnection { implicit connection =>
      ....
    }
  }
}

当然,如果你想注入一个特定的数据库(而不是"default"),你可以像这样注释属性:

import play.api.db.Database
import play.db.NamedDatabase

@Singleton
class ProductService @Inject() (@NamedDatabase("customers") database: Database) {

  def save(product: Product) = {
    database.withConnection { implicit connection =>
      ....
    }
  }
}

并且,在您的测试中,您可以根据需要创建Database并手动将其注入您的服务。查看有关如何执行此操作的详细信息at the docs