Scala+Slick 3: вставка результата одного запроса в другую таблицу

этот вопрос касается slick 3.0 или 3.1 (я гибок в этом)

у меня есть промежуточный запрос, который я обрабатываю с map, for, etc. чтобы получить желаемый результат. В конце концов у меня есть

val foo: DBIOAction[Seq[MySchema.Bar], NoStream, Effect.Read]

теперь у меня есть val bar: TableQuery[MySchema.Bar] и я хочу вставить в него фу.

если foo будет Seq я мог бы просто сделать bar ++= foo, но это не так.

единственный способ, который я нашел, - это материализовать результат, ожидая его. Как это

val query = (bar ++= Await.result(db.run(foo), Duration.Inf))

очевидно query необходимо запустить в какой-то момент с db.run. Но теперь у меня есть два DB-runs. Не лучше ли иметь все сразу?

есть ли лучший способ сделать это?

2 ответов


DBIOAction и map/flatMap функции, поэтому вы можете написать что-то вроде

val insertAction = foo.flatMap(bar ++= _)

на insertAction будет типа DBIOAction[Int, NoStream, Effect.Write] или что-то в этом роде (я не совсем уверен насчет Int и эффект), то вы можете запустить его в БД как любой DBIOAction С помощью db.run; то, что вы получаете, - это будущее общего запроса и результат вставки.


на вопросы уже ответили, но я пришел сюда в поисках другого решения, так что, возможно, это будет полезно для других людей.

как говорит @Aldo, мы хотим работать на уровне DBIO, насколько это возможно, но я бы пошел дальше и сказал, что вы должны работать на Query level насколько это возможно, поскольку это компилируется в один оператор sql, который может быть отправлен в базу данных.

например, вставка из select должна быть скомпилирована в INSERT INTO table1 SELECT.... Если вы используете несколько DBIOS с помощью flatMap, как было предложено, это будет скомпилировано в SELECT, значения будут приведены в память, а затем INSERT оператор будет скомпилирован, интерполируя значения в строке, и этот новый запрос будет отправлен в базу данных. На самом деле это может быть намного медленнее, если ваш select возвращает много результатов, и это может истощить вашу память в худшем случае.

Итак, чтобы скомпилировать что-то подобное в один запрос, вы можете написать:

val bar: TableQuery[MySchema.Bar]

val foo: Query[MySchema.Bar, Bar, Seq]

val insert: DBIO[Int] = bar.forceInsertAll(foo)