Вы начинаете вычисления, вызывая itemsToDBController.saveItems(items)
, а затем немедленно возвращаете результат с помощью Ok("Success")
.Поэтому после запроса может быть сгенерировано исключение.
Чтобы устранить эту проблему, необходимо преобразовать результат itemsToDBController.saveItems
из List[Future[T]]
в Future[List[T]]
с помощью Future.sequence
.Затем вызовите метод map
для возвращенного будущего.Вызовите recover
для этого Future
, чтобы узнать, какая ошибка выдана:
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, проверьте этот официальный документы