简体   繁体   中英

PlayFramework: how to inject database object

I'm using anorm for play framework and I have the following service class:

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

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

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

Two issues here:

1) I do not wish to add the line private val DB = dbApi.database("default") in each Service class. What is the best way to abstract this?

2) I would also like to have the datasource configurable so that I can pass test datasource when writing Integration tests

Test class:

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

}

Any suggestions?

You can inject the database object itself instead of a DBApi . By the way, one of Guice best practices is to inject only direct dependencies . So, your example could be something like:

import play.api.db.Database

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

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

Of course, if you want to inject a specific database (instead of the "default" one), you can just annotate the property like this:

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 =>
      ....
    }
  }
}

And, at your tests, you can just create the Database as you want and manually inject it to your service. See more details about how to do it at the docs .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM