0

scala Play に play-slick を使用しています! ダミーレスト API。

そのため、複数のテーブルからレコードをフェッチする必要があります。しかし、それらは相互に依存しています。

Table_1   Table_2
id1       id2
id2

Table_2 からレコードをフェッチするには、Table_1 からレコードをフェッチしてから、Table_2 から id2 フェッチを使用する必要があります。

私のコントローラー:

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: 私は関数型パラダイムとスカラに非常に慣れていないので、できれば私の無知を許してください。

4

1 に答える 1

1

問題を簡単に解決するには:

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)
  }
}

ここでの問題は、scalaflatMap OptionFuture一緒にできないことです。これは、このトピックに関する素晴らしいシンプルな記事です (FutureOソリューションとしてのカスタムモナド実装を使用)。簡単に言うと、catsライブラリ (または scalaz ライブラリ) とOptionT機能を使用します。コードを少し簡略化しました。

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))
}

flatMapこれで、このモナドを簡単に処理できるようになり、 orOptionTを扱っているかどうかは気にしなくなりました (scala での理解は構文糖衣にすぎません)。OptionFuture

于 2016-06-12T08:04:41.987 に答える