问题描述
我正在为我的scala Play使用play-slick!虚拟休息API.
I am using play-slick for my scala Play! dummy rest API.
因此,我必须从多个表中获取记录.但是,它们是相互依存的,即
So, I have to fetch records from multiple tables. But, they are interdependent, i.e.
Table_1 Table_2
id1 id2
id2
要从Table_2中获取记录,我必须从Table_1中获取记录,然后使用id2从Table_2中获取.
To fetch a record from Table_2 I have to fetch a record from Table_1 and then using id2 fetch from Table_2.
我的控制器:
def getEntity(id : Long) = Action.async {
table1DAO.findById(id) map { t1 =>
t1 map { t1Entity =>
table2DAO.findById(t1Entity.id2) map { t2 =>
t2 map { t2Entity =>
Ok(Json.toJson(CombiningClass(t1Entity, t2Entity)))
} getOrElse { Ok(Json.toJson(t1Entity)) }
}
} getOrElse { NoContent }
}
}
编译后,我得到:
[error] DummyController.scala:17: overloaded method value async with alternatives:
[error] [A](bodyParser: play.api.mvc.BodyParser[A])(block: play.api.mvc.Request[A] => scala.concurrent.Future[play.api.mvc.Result])play.api.mvc.Action[A] <and>
[error] (block: play.api.mvc.Request[play.api.mvc.AnyContent] => scala.concurrent.Future[play.api.mvc.Result])play.api.mvc.Action[play.api.mvc.AnyContent] <and>
[error] (block: => scala.concurrent.Future[play.api.mvc.Result])play.api.mvc.Action[play.api.mvc.AnyContent]
[error] cannot be applied to (scala.concurrent.Future[Object])
[error] def getEntity(id : Long) = Action.async {
[error] ^
[error] one error found
这是我的DAO方法:
def findById(id : Long): Future[Option[A]] = {
db.run(tableQ.filter(_.id === id).result.headOption)
}
PS:我对功能范式和Scala还是很陌生,所以,如果可以的话,请原谅我的无知.
PS: I'm very new to functional paradigm and scala, so if you can, pardon my ignorance.
推荐答案
要简单地解决您的问题,
To simply solve your problem:
def getEntity(id : Long) = Action.async {
findById(id) flatMap {
case Some(t1Entity) =>
findById(t1Entity.id2) map { t2Opt =>
t2Opt map { t2Entity =>
Ok(Json.toJson(t1Entity, t2Entity))
} getOrElse { Ok(Json.toJson(t1Entity)) }
}
case None => Future.successful(NoContent)
}
}
这里的问题是您不能在Scala中一起flatMap
Option
和Future
. 此处是关于该主题的精彩而简单的文章(带有自定义FutureO
monad实现作为解决方案).长话短说,我会使用 cats 库(甚至是scalaz库)和OptionT
功能.我稍微简化了您的代码.
The problem here is that you can't flatMap
Option
and Future
together in scala. Here is a fantastic and simple article concerning this topic (with the custom FutureO
monad implementation as a solution). Long story short, I would use the cats library (or even scalaz library) and OptionT
feature. I slightly simplified your code.
def getEntity(id : Long) = Action.async {
(for {
t1 <- daoFindById(id)
t2 <- daoFindById(t1.id2)
} yield (t1, t2)).map{
result => Ok(Json.toJson(result))
}.getOrElse(NoContent)
}
case class T(id2: Long)
def daoFindById(id : Long): OptionT[Future, T] = {
OptionT[Future, T](db.run(tableQ.filter(_.id === id).result.headOption))
}
您现在可以轻松地在该OptionT
单子上使用flatMap
,并且不管您是在处理Option
还是Future
(因为对scala的理解只是语法糖).
You can now easily flatMap
over this OptionT
monad, and don't care if you are dealing with Option
or Future
(for comprehension in scala is only a syntactic sugar).
这篇关于Scala Play未来的相互依存关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!