Как я могу запускать взаимозависимые запросы вместе с операциями, не относящимися к БД, в той же транзакции, используя slick - PullRequest
0 голосов
/ 25 июня 2018

Учитывая модель данных (<- указывает на зависимость внешнего ключа) </p>

TableA <- TableB <- TableC
   ^                 v
    -----------------

Мне нужно выполнить операцию API DELETE API, которая мягко удаляет строку в TableC.Это удаление также должно инициировать вызов другой службы (требующей значений из TableA и TableB), если больше нет восстановленных записей TableC, которые ссылаются на родителя этой строки в TableB.Если внешний вызов не удастся, я хочу отменить мягкое удаление.Я хочу сделать все это идиоматическим способом (я фактически новичок в scala / slick) и использую транзакции для отката

На основании прочитанного я должен использовать дляпонимание, чтобы собрать запросы, но у меня есть проблемы с получением операций базы данных, чтобы хорошо сочетаться с внешним вызовом службы.Мой первоначальный план был:

val select = for {
  tableCRow <- tableBDao.TableQueryC.filter(_.id === idParam)
  tableBRow <- tableBDao.TableQueryB if tableCRow.tableBForeignKey === tableBRow.id
  tableARow <- TableADao.TableQueryA if tableCRow.tableAForeignKey === tableARow.id
  count <- tableBDao.TableQueryC.filter(_.tableBForeignKey === tableBRow.id).map(_.id).countDefined
  _ <- tableBDao.softDeleteRow(idParam)
  _ <- if (count > 1) DBIO.successful(httpRequestService.deleteOtherResource(tableARow.someValue, tableBRow.someValue))
} yield ()
db.run(select.result)

Но у него были проблемы, потому что я не мог передать значения Rep [T] Слика моему методу httpRequestService.Затем я попытался разбить его на две части - сначала ВЫБРАТЬ, а затем УДАЛИТЬ, вот так:

val select = for {
  tableCRow <- tableBDao.TableQueryC.filter(_.id === idParam)
  tableBRow <- tableBDao.TableQueryB if tableCRow.tableBForeignKey === tableBRow.id
  tableARow <- TableADao.TableQueryA if tableCRow.tableAForeignKey === tableARow.id
  count <- tableBDao.TableQueryC.filter(_.tableBForeignKey === tableBRow.id).map(_.id).countDefined
} yield (tableBRow.date.formatted("yyyy-MM-DD"), tableARow.externalServiceId, count)
val result: Future[Option[(String, Long, Integer)]] = db.run(select.result.headOption)
result.map {
  case None => throw new IllegalArgumentException("exception message")
  case Some(data) =>
    val delete = for {
      _ <- tableBDao.softDeleteRow(idParam)
      _ <- if (data._3 > 1) DBIO.successful(httpRequestService.cancelSchedulerJob(data._2, data._1))
    } yield numRows
    db.run(delete.transactionally)
}

Но, несмотря на то, что это на самом деле проходит проверки IntelliJ IDEA, он не скомпилируется как мой запрос countвозвращает Rep [Int], в котором отсутствует функция map.Кроме того, каждая из таблиц строк моей таблицы (A | B | C) вызывает ошибку, потому что они ожидают slick.lifted.Query[Nothing,Nothing,Seq] и получают slick.lifted.Query[Nothing,T,Seq].Наконец, оператор db.run не хочет использовать headOption и, по-видимому, возвращает Any, который не поддерживает map

halp

1 Ответ

0 голосов
/ 05 июля 2018

Решил это, наконец, поняв, как гладко складывает вещи вместе для понимания.Я должен был вывести счет из запроса и в следующую функцию groupby-> map, которая накапливала мой список вещей, которые я хотел посчитать, и ТОГДА посчитал их в отличие от подсчета как части запроса.Это также исправило все остальные проблемы, так как запрос подсчета отбрасывал ожидаемые типы возврата всего остального.

В основном решение выглядело так (вещь1 была для соединения):

val select = (for {
  thing1 <- query1
  thing2 <- query2
  thing3 <- query3
  listToCount <- query4 selecting everything I wanted to count
} yield (thing2, thing3, listToCount))
  .groupBy({
    case (thing2, thing3, listToCount) =>
      (thing2, thing3)
  })
  .map({
    case ((thing2, thing3), list) =>
      (thing2.deliveryDate, thing3.schedulerJobId, list.map(_._3).length)
  })
...