【问题标题】:Asynchronous wait for database-value in Playframework (2.4-M3) and Slick (3.0.0-RC3)Playframework (2.4-M3) 和 Slick (3.0.0-RC3) 中的数据库值的异步等待
【发布时间】:2015-04-09 15:07:27
【问题描述】:

我想让我的应用程序尽可能异步。现在我有了这个存储库:

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}”这样的 url 时,我想检查给定的语言(代码)是否确实存在。比如,如果该网站没有法语 (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 异步文档,但我无法真正按预期工作。

任何意见表示赞赏!

【问题讨论】:

  • 首先,异步!=非阻塞。你为什么说“这行不通”,你的 find 返回一个 Future[Language] 所以它是异步的(但不是非阻塞的)并且你有一个 onComplete 处理程序来呈现结果。什么不完全有效?
  • @vptheron 该方法必须返回一个Action,因此无法编译,因为返回值在“onComplete{}”块中

标签: scala asynchronous playframework slick


【解决方案1】:

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

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

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

}

【讨论】:

    【解决方案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) 应该返回OptionLanguage。将Future[Language] 更改为Future[Result] 并使用Action.async 而不是Action

    现在解释一下,Action 接受一个结果应该是Result 的块。然而,你得到的是Future[Option[Language]]。 Play 为需要Future[Result]Action 提供了async 方法,它负责完成请求。

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

     lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
    

    我们映射 lang,如果 Option[Language] 不是 None 则我们将其转换为 Ok("yay") 否则我们将其转换为 NotFound

    即使,如果你没有得到Option[Language],想法还是一样的。将Future[Language] 转换为Future[Result] 并使用Action.async 而不是Action

    【讨论】:

    • Sorre(非母语人士)我真的不明白你在做什么。我在哪里将“Future[Language]”更改为“Future[Result]”?在我的存储库中,我假设?在控制器中,我将其留在 Future[Option[Language]]?因为 Result 没有地图功能?!但是那样它就不会编译,所以我想我在这里遗漏了一些东西。您能否解释一下我需要在控制器中更改什么以及在存储库中更改什么?谢谢!
    • 试试这个,val lang:Future[Option[Language]] = languageRepository.find(language); lang.map(l => Ok("Yay")) 并使用 Action.async 代替 Action
    • 谢谢,但这显然无法编译。 “find”方法返回 Future[Language] 而不是“Future[Option[Language]]”
    • 哎呀..我的意思是 val lang:Future[Language] = languageRepository.find(language); lang.map(l => Ok("Yay")) 并使用 Action.async 而不是 Action .. map 也在 Future 上定义。
    • 有效,但现在当然没有“其他”部分。我可以以某种方式合并它吗?如果控制器找不到语言(如 domain.tld/test/),它会抛出 NoSuchElementException,我想直接在控制器中处理它。
    猜你喜欢
    • 2018-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    • 2021-10-04
    相关资源
    最近更新 更多