与未来的隐式转换

Implicit conversion with future

我在从 DB 模型到 APP 模型的隐式转换中遇到问题:

  override implicit def dbBook2AppBook(book: Book): BookApp = {
      val author = Await.result(authRep.getById(book.authID),1 seconds)
      BookApp(book.id.get, book.title, 
              AuthorApp(author.get.id,author.get.name,author.get.surname), book.available)
  }

基本上我想将 Book 转换为 BookApp:

case class BookApp(id: Int,
                   title: String,
                   author: AuthorApp,
                   var available: Boolean)

case class Book(id: Option[Int] = None, title: String, authID: Int, available: Boolean)

如您所见,我的书 class 有作者 ID,我希望我的 BookApp 中有 AuthorApp 对象。我需要做的是从数据库 Author 中获取,同时从 Book 中进行转换。从数据库通过 authRep: AuthorReposiotory 我获得了 Future[Author].

我的问题是,是否有更好的方法从转换中获取 BookApp 而无需使用等待 Author 对象?有什么建议吗?

编辑

对于“Jon Anderson”的回答,我无法从 Future[Book] 转换为 Future[BookApp],因为当我从数据库中获取不止一行时,我收到 Future[Seq[Book]],那么转换将不起作用。附加信息,我仍然在整个应用程序中保留 Future,因为当我进行转换时,我会做这样的事情:

  def findBooks(title: Option[String], authorName: Option[String], 
                authorSurname: Option[String], available: Option[Boolean])
                : Future[Seq[BookApp]] = {
    bookRep.findBooks(title,authorName,authorSurname,available)
                      .map(x => x.map( y => y: BookApp))
  }

所以转换是通过映射在对象上完成的,但仍然返回转换后的未包装对象。主要问题是等待转换,所以主要问题是,我怎样才能摆脱它?

您应该将未来一直保留到应用程序层。在这种情况下,for-comprehension 效果很好...

override implicit def dbBook2AppBook(bookFuture: Future[Book]): Future[BookApp] = { 
    for {
       book <- bookFuture
       author <- authRep.getById(book.authID)
       //any other futures needed to create APP model here...
    } yield {
        BookApp(book.id.get, book.title, AuthorApp(author.get.id,author.get.name,author.get.surname), book.available)
    }
}

正如您发现的类型:您不能。

首先,在您更加熟悉这些语言之前,不要在您的设计中使用隐式,它们在这里对您没有帮助。 (并且永远忘记 隐式转换 ...)

一种可能的方法是在 Future 上下文中继续工作,起诉 dbBook2FutureAppBook(book: Book): Future[BookApp]

可以使用 Future#flatMapFuture.sequence:

Future[Seq[Book]] 转换为 Future[Seq[Bookapp]]
val fsb: Future[Seq[Book]] = ...

val fsa: Future[Seq[Bookapp]] =
  fsb.flatMap { books => 
    Future.sequence(books.map(dbBook2FutureAppBook))
  }

这回答了您关于 Future 的问题,但请注意,这将在您的 Future[Seq[Book]] 中为每本书发出一个数据库查询,这是一个糟糕的主意。您可能想手动编写一个 Seq[Book] => Seq[Bookapp] 查询。