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)