异步等待Playframework(2.4-M3)和Slick(3.0.0-RC3)中的数据库值

时间:2015-04-09 15:07:27

标签: scala asynchronous playframework slick

我希望尽可能保持我的应用程序异步。现在我有了这个存储库:

object LanguageRepository extends LanguageRepositoryTrait
{
    private val languages = TableQuery[Languages]
    private def db:Database = Database.forDataSource(DB.getDataSource())

    private def filterQuery(id: Long): Query[Languages, Language, Seq] = languages.filter(_.id === id)
    private def filterCode(code: String): Query[Languages, Language, Seq] = languages.filter(_.code === code)
    private def all() : Query[Languages, Language, Seq] = languages

    override def find(id: Long): Future[Language]  =
    {
        try db.run(filterQuery(id).result.head)
        finally db.close()
    }

    override def find(code: String): Future[Language] =
    {
        try db.run(filterCode(code).result.head)
        finally db.close()
    }

    override def get(): Future[Seq[Language]] =
    {
        try db.run(all().result)
        finally db.close()
    }
}

当我打电话给" domain.tld / {language}"我想检查给定的语言(代码)是否确实存在。比如,如果网站不是法语(fr),我想抛出异常或404。

现在,我的问题是,整个异步的事情非常酷,虽然我确实想要理解它背后的理论,但我现在感到困惑。我的意思是,我希望这是非阻塞的(并且异步,这是我使用Future和async的原因;)

在我的控制器中,我想做类似的事情:

def checkLanguage(language:String) = Action
{
  val lang:Future[Language] = languageRepository.find(language)

 lang.onComplete
 {
   case Success(s) = Ok("Yay")
   case Failure(f) = 404("Oh no!")
 }
}

当然这不起作用,但那是我想要让事情发挥作用的模式。我想等待或推迟网站的呈现,直到它确认给定的语言代码有效或无效。

我查看了2.3.6(https://www.playframework.com/documentation/2.3.6/ScalaAsync)的Playframeworks异步文档,但我无法按照预期的方式工作。

任何意见都赞赏!

2 个答案:

答案 0 :(得分:2)

试试这个,

Action.async {
    val lang:Future[Option[Language]] = languageRepository.find(language)
    lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
} 

首先,我假设如果某种语言不存在,那么languageRepository.find(language)应该返回Option Language。将Future[Language]更改为Future[Result]并使用Action.async代替Action

现在有一些解释,Action采用一个块,其结果应为Result。但是,你得到的是Future[Option[Language]]。 Play为需要async的{​​{1}}提供Action方法,并负责完成请求。

因此,您需要将Future[Result]转换为Future[Option[Language]]

Future[Result]

如果 lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!")) 不是Option[Language],我们会映射到lang,然后我们会将其转换为None,否则我们会将其转换为Ok("yay")

即使如果你没有得到NotFound,这个想法仍然是一样的。将Option[Language]转换为Future[Language]并使用Future[Result]代替Action.async

答案 1 :(得分:1)

从您的数据库查询中不要使用.head而是使用.headOption。那样你的返回类型将是Future [Option [x]]

在你的控制器你可以做这样的事情

Lang.map { case Some (x) => Ok (x)
  case None =>  404 ( "not found ")

}