2016-01-23 2 views
5

Этот вопрос о скользком 3.0 или 3.1 (Я гибкий о том, что)Скалы + сликовые 3: Вставка результата одного запроса в другую таблицу

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

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

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

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

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

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

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

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

+0

'бар + = Foo'? Но вам все равно придется 'db.run', независимо от того, является ли это' + = 'или' ++ = '... (?) – kornfridge

+0

Я думаю, что ++ = с побочными эффектами был slick2 api, а slick3 более функциональный, поэтому он требует, чтобы вы явно делали 'db.run' – kornfridge

+0

Да, результат ++ = теперь является запросом, который нужно запустить. Я отредактировал вопрос в этом вопросе. Но я должен сделать два вызова db.run для этой задачи. – masgo

ответ

4

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

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

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

+0

«FlatMap» делает трюк. В итоге у меня осталось только одно DBIOAction, которое мне нужно запустить. Я столкнулся с другим вопросом с этой темой: когда мне следует делать db.run()? Вот пример 'val foo = db.run (persons.result.map (_. map {p => tr (td (p.id))})) 'Я могу сделать это так, или я могу закончить часть' db.run' после '.result '. Оба метода дают мне то же «будущее», есть ли разница в производительности? – masgo

+2

Как правило, вы хотите работать на уровне «DBIO», насколько это возможно; когда вы вызываете 'db.run' slick, будет выполняться столько запросов, сколько потребуется, используя собственный контекст выполнения, и он вернет вам« Будущее ». Я думаю, что есть потенциальная разница в производительности, если вы сделаете так, чтобы slick оптимизировал использование потоков в отношении доступа к БД. –

1

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

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

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

Так собрать что-то вроде этого в одном запросе вы можете написать:

val bar: TableQuery[MySchema.Bar] 

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

val insert: DBIO[Int] = bar.forceInsertAll(foo) 
Смежные вопросы