Scala Playframework并不是所有的DB查询都能执行



我通过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信息,请查看此官方文档

最新更新