我通过HTTP Post Request向我的Playframework后端发送Json。
在我的后台,我将Json验证为模型。之后,我想将模型中的条目保存到数据库中。
def parseJSON: Action[AnyContent] = Action.async {
request =>
Future {
request.body.asJson.map(_.validate[MyModel] match {
case JsSuccess(items, _) =>
itemsToDBController.saveItems(items)
Ok("Success")
case JsError(err) =>
println(err)
BadRequest("Json Parse Error")
}).getOrElse(BadRequest("Error"))
}
}
一个项目由多个对象组成。要将所有对象保存到数据库中,我需要获取一些值。因此,我使用for(..(yield(…(:
def saveItems(items: MyModel) = {
items.SomeObject.map(obj => {
if (obj.value1.isDefined &&
obj.value2.isDefined ) {
val result = for (
value1Exists <- value1DTO.checkExists(obj.value1.name);
value1Entry <- getOrCreateValue1(value1Exists, obj);
value2Exists <- value2DTO.checkExists(obj.value2.name);
value2Entry <- getOrCreateValue2(value1Exists, obj)
) yield(value1Entry, value2Entry)
result.map({
case (value1Entry, value2Entry) => {
insertAllValue3(value1Entry, value2Entry)
Future.successful()
}
case _ => Future.failed(new Exception("Not all entries defined"))
})
}
else {
Future.successful("Not all objects defined - skipping")
}
})
}
我的问题是,在所有result.map({...})
启动后,我的parseJSON操作returns 200 - OK
。但并不是所有相关的项目都存储到我的数据库中。似乎在200 - OK
之后,一切都停止了,甚至没有抛出错误。我不想在我的操作中使用Await.result或任何阻塞。
提前感谢
通过调用itemsToDBController.saveItems(items)
开始计算,然后立即用Ok("Success")
返回结果。所以在请求完成后可能会抛出异常。
要解决这个问题,您需要在Future.sequence
的帮助下将itemsToDBController.saveItems
的结果从List[Future[T]]
转换为Future[List[T]]
。然后对返回的future调用map
方法。在此Future
上调用recover
以查找抛出的错误:
def parseJSON: Action[AnyContent] = Action.async { request =>
request.body.asJson
.map(_.validate[MyModel] match {
case JsSuccess(items, _) =>
Future
.sequence(itemsToDBController.saveItems(items))
.map(_ => Ok("Success"))
.recover {
case e: Exception => BadRequest(e.getMessage())
}
case JsError(err) =>
println(err)
Future.successful(BadRequest("Json Parse Error"))
})
.getOrElse(Future.successful(BadRequest("Error")))
}
更新
为了在一个事务中运行所有插入,您应该组合DBIOAction
而不是Future
。例如,您将checkExists(name)
重写为:
def checkExists(name: String): DBIO[Boolean] = {
Objects.filter(obj => obj.name === name).exists
}
getOrCreateValue(exists, obj)
作为:
def getOrCreateValue(exists: boolean, obj: Object): DBIO[Object] = {
if (exists) {
Objects.filter(o => o.name === name).result.head
} else {
(Objects returning Objects.map(_.id) into ((o, id) => o.copy(id = Some(id)))) += obj
}
}
现在您可以通过以下方式在单个事务中运行它:
def saveItems(items: MyModel) = {
val insertActions = items.SomeObject.map(obj => {
if (obj.value1.isDefined && obj.value2.isDefined) {
val result = for {
value1Exists <- value1DTO.checkExists(obj.value1.name);
value1Entry <- getOrCreateValue1(value1Exists, obj);
value2Exists <- value2DTO.checkExists(obj.value2.name);
value2Entry <- getOrCreateValue2(value1Exists, obj)
} yield (value1Entry, value2Entry)
result.flatMap({
case (value1Entry, value2Entry) => {
insertAllValue3(value1Entry, value2Entry) // This also returns instance of `DBIOAction`
}
case _ =>
DBIO.failed(new Exception("Not all entries defined"))
})
} else {
DBIO.successful("Not all objects defined - skipping")
}
})
db.run(DBIO.sequence(inserActions).transactionally)
}
有关如何使用DBIO操作的mo信息,请查看此官方文档