Assign dynamically injected database name in Play Slick

◇◆丶佛笑我妖孽 提交于 2019-12-24 05:35:08

问题


I have the following Play Slick DAO class. Note that the database configuration is a constant control0001. The DAO has a function readUser that reads a user based on its user id:

class UsersDAO @Inject()(@NamedDatabase("control0001") 
    protected val dbConfigProvider: DatabaseConfigProvider) 
                  extends HasDatabaseConfigProvider[JdbcProfile] {

   import driver.api._

   def readUser (userid: String) = {
      val users = TableQuery[UserDB]
      val action = users.filter(_.userid === userid).result
      val future = db.run(action.asTry)
      future.map{
        case Success(s) => 
          if (s.length>0)
            Some(s(0))
          else
            None
        case Failure(e) => throw new Exception ("Failure in readUser: " + e.getMessage)
      }
   }
}

Instead of having a constant in @NamedDatabase("control0001"), I need the database to be variable. In the application, I have multiple databases (control0001, control002 and so on) configured in application.conf. Depending on a variable value, I need to determine the database to be used in the DAO. All the databases are similar and have the same tables (the data in each database differs).

The following Play class calls the DAO function, but first it needs to determine the database name to be injected:

class TestSlick  @Inject()(dao: UsersDAO) extends Controller  {

  def test(someCode: Int, userId: String) = Action { request =>

    val databaseName = if (someCode == 1) "control0001" else "control0002"

    // Run the method in UsersDAO accessing the database set by databaseName

    val future = dao.readUser(userId) 
    future.map { result =>
      result match {
        case Some(user) => Ok(user.firstName)
        case _ => Ok("user not found")
      }
    }
  }        
}

How can this be achieved in Play Slick?


回答1:


You can try to initialize slick db object overriding default config:

val db = Database.forURL("jdbc:mysql://localhost/" + databaseName, driver="org.h2.Driver")

more information in slick docs http://slick.lightbend.com/doc/3.0.0/database.html




回答2:


Instead of trying to use Play's runtime dependency injection utilities in this case, use the SlickApi directly in your DAO and pass the datasource name to the dbConfig(DbName(name)) method. To obtain the SlickApi, mix in the SlickComponents trait:

class UsersDAO extends SlickComponents {

  def readUser(userid: String, dbName: String) = {
    val users = TableQuery[UserDB]
    val action = users.filter(_.userid === userid).result

    val dbConfig = slickApi.dbConfig(DbName(dbName))
    val future = dbConfig.db.run(action.asTry)
    ...
  }
}

Then in your controller:

def test(someCode: Int, userId: String) = Action { request =>

  val databaseName = if (someCode == 1) "control0001" else "control0002"
  val future = dao.readUser(userId, databaseName)
  ...
}


来源:https://stackoverflow.com/questions/47493031/assign-dynamically-injected-database-name-in-play-slick

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!