我正在使用Slick 1.0.1运行Scala Play 2.2应用程序。我试图将所有数据库调用包装到将来的尝试中,例如:
object DbTeachers extends Table[DbTeacher]("edu_teachers") {
...
def insertTeacher(school: Int, userId: String)
(implicit ec: ExecutionContext, db: Database) =
future { Try { db.withSession => { implicit s: Session =>
(DbTeachers.school ~ DbTeachers.teacher).insert(school, userId)
}}}
}
我发现模式future { Try { db.withSession => { ACTUAL_CODE_GOES_HERE }}}
会造成混乱,我想按如下方式抽象出来:
sealed class DbAsync[T](block: => T) {
import play.api.libs.concurrent.Execution.Implicits.defaultContext
implicit lazy val db = Database.forDataSource(DB.getDataSource())
def get: Future[Try[T]] = future { Try { db.withSession { implicit s: Session =>
block
}}}
}
object DbAsync {
def apply[T](block: => T): Future[Try[T]] = new DbAsync[T](block).get
}
然后我可以将insertTeacher函数编写为:
def insertTeacher(school: Int, userId: String) = DbAsync {
(DbTeachers.school ~ DbTeachers.teacher).insert(school, userId)
}
然而,scala编译器(2.10.2)抱怨这个:could not find implicit value for parameter session: scala.slick.session.Session
根据我的理解,insert()
方法在DbAsync块中的范围内确实有一个隐式会话变量,并且因为它是一个按名称调用的参数,所以它实际上不应该被评估,直到它是在DbAsync中调用,此时范围内会有一个隐式会话对象。
所以,我的问题是,如何说服Scala编译器在范围内确实存在隐式Session对象?
答案 0 :(得分:8)
您的建议不正确。在哪里评估call-by-name
参数并不重要。所有隐式参数都应在编译时在需要它们的地方解析。
你可以这样做:
def dbAsync[T](block: Session => T): Future[Try[T]] = {
import play.api.libs.concurrent.Execution.Implicits.defaultContext
implicit lazy val db = Database.forDataSource(DB.getDataSource())
future { Try { db.withSession { block }}}
}
def insertTeacher(school: Int, userId: String) = dbAsync { implicit s: Session =>
(DbTeachers.school ~ DbTeachers.teacher).insert(school, userId)
}
请注意,您不需要课程DbAsync
也不需要DbAsync
。
请注意,您不应使用defaultContext
进行阻止操作。您可以使用已配置的线程池创建其他ExecutionContext
。