与未来的隐式转换
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#flatMap
和 Future.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]
查询。
我在从 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#flatMap
和 Future.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]
查询。