У меня возникли проблемы с пониманием нового Slick DBIOAction
API, для которого, похоже, не так много примеров в документации. Я использую Slick 3.0.0, и мне нужно выполнить некоторые действия с БД, а также некоторые вычисления с данными, полученными из базы данных, но все эти действия должны быть выполнены внутри одной транзакции. Я пытаюсь сделать следующее:
- Выполнить запрос к базе данных (таблица
types
). - Выполните некоторую агрегацию и фильтрацию результатов запроса (этот расчет нельзя выполнить в базе данных).
- Выполните другой запрос, основанный на вычислениях из шага 2 (таблица
messages
— из-за некоторых ограничений этот запрос должен быть в чистом SQL). - Соедините данные из шага 2 и 3 в памяти.
Я хочу, чтобы запросы из шагов 1 и 3 выполнялись внутри транзакции, так как данные из их наборов результатов должны быть согласованы.
Я пытался сделать это в монадическом стиле соединения. Вот слишком упрощенная версия моего кода, но я даже не могу его скомпилировать:
val compositeAction = (for {
rawTypes <- TableQuery[DBType].result
(projectId, types) <- rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10)))
counts <- DBIO.sequence(types.map(aType => sql"""select count(*) from messages where type_id = ${aType.id}""".as[Int]))
} yield (projectId, types.zip(counts))).transactionally
- Первая строка понимания
for
выбирает данные из таблицыtypes
. - Предполагается, что вторая строка
for
понимания выполняет некоторую группировку и нарезку результатов, в результате чего получаетсяSeq[(Option[String], Seq[String])]
- Третья строка понимания
for
должна выполнить набор запросов для каждого элемента из предыдущего шага, в частности, она должна выполнить один SQL-запрос для каждого из значений внутриSeq[String]
. Итак, в третьей строке я строю последовательность изDBIOAction
s. - Пункт
yield
zip
stypes
из второго шага иcounts
из третьего шага.
Эта конструкция, однако, не работает и дает две ошибки времени компиляции:
Error:(129, 16) type mismatch;
found : slick.dbio.DBIOAction[(Option[String], Seq[(com.centreit.proto.repiso.storage.db.models.DBType#TableElementType, Vector[Int])]),slick.dbio.NoStream,slick.dbio.Effect]
(which expands to) slick.dbio.DBIOAction[(Option[String], Seq[(com.centreit.proto.repiso.storage.db.models.TypeModel, Vector[Int])]),slick.dbio.NoStream,slick.dbio.Effect]
required: scala.collection.GenTraversableOnce[?]
counts <- DBIO.sequence(types.map(aType => sql"""select count(*) from messages where type_id = ${aType.id}""".as[Int]))
^
Error:(128, 28) type mismatch;
found : Seq[Nothing]
required: slick.dbio.DBIOAction[?,?,?]
(projectId, types) <- rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10)))
^
Я попытался обернуть вторую строку в DBIOAction
, используя DBIO.successful
, который должен поднимать постоянное значение в монаду DBIOAction
:
(projectId, types) <- DBIO.successful(rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10))))
Но в этом коде переменная types
подразумевается как Any
, и из-за этого код не компилируется.
_
). В моем случае одно из моих действий вообще не имеет ничего общего с базой данных, и все действия возвращают результаты, которые используются в других включениях или вyield
. - person Sergei   schedule 29.06.2015