【发布时间】:2016-02-28 11:45:40
【问题描述】:
我正在尝试执行可能很简单的操作,但遇到了困难:我有一个在 Mongo 中创建用户的 Play 控制器,但我首先要验证是否没有用户具有相同的电子邮件地址.我的用户对象上有一个函数,它通过电子邮件地址搜索用户并返回 Future[Option[User]]:
def findByEmail(email: String): Future[Option[User]] = {
collection.find(Json.obj("email" -> email)).one[User]
}
我通过电子邮件搜索用户的控制器功能有效:
def get(id: String) = Action.async {
User.findById(id).map {
case None => NotFound
case user => Ok(Json.toJson(user))
}
}
我有一个创建用户的函数:
def create(user:User): Future[User] = {
// Generate a new id
val id = java.util.UUID.randomUUID.toString
// Create a JSON representation of the user
val json = Json.obj(
"id" -> id,
"email" -> user.email,
"password" -> user.password,
"firstName" -> user.firstName,
"lastName" -> user.lastName)
// Insert it into MongoDB
collection.insert(json).map {
case writeResult if writeResult.ok == true => User(Some(id), user.email, user.password, user.firstName, user.lastName)
case writeResult => throw new Exception(writeResult.message)
}
}
并且相应的控制器功能起作用:
def post = Action.async(parse.json) {
implicit request =>
request.body.validate[User].map {
user => User.create(user).map {
case u => Created(Json.toJson(u))
}
}.getOrElse(Future.successful(BadRequest))
}
但是当我修改 post 方法以首先检查具有指定电子邮件的用户时,它失败了:
def post = Action.async(parse.json) {
implicit request =>
request.body.validate[User].map {
user => User.findByEmail(user.email).map {
case None => User.create(user).map {
case u => Created(Json.toJson(u))
}
case u => BadRequest
}
}.getOrElse(Future.successful(BadRequest))
}
它报告说,虽然它期望一个 Future[Result],但它找到了一个 Future[Object]。我认为这个错误意味着它最终找到了一个 Future[Future[Result]],这不是它所期望的。
我的问题是:将此类调用链接在一起的最佳做法是什么?我应该添加一个 Await.result() 调用来等待第一个操作完成后再继续吗?这会导致发生任何不需要的同步操作吗?或者有没有更好的方法来解决这个问题?
提前致谢!
【问题讨论】:
-
当然
Await会添加同步,这是不想要的。错误是由于Future内部的异质值造成的。确保所有情况的返回类型都相同。
标签: scala playframework