Несколько вставок в одной транзакции с Slick 3.0

Я занимаюсь обновлением своего приложения Play Framework, используя slick 2.1.0, до play-slick 1.0.0 (включая slick 3.0.0).

У меня возникли некоторые проблемы с пониманием того, как обрабатываются транзакции.

Допустим, у меня есть следующий фрагмент кода:

db.withTransaction { implicit session =>
    for (id <- ids) yield someTable.insert(SomeObject(id))
}

Как это сделать в slick 3? Я хочу, чтобы все объекты были вставлены в одну транзакцию. Если один объект не может быть вставлен, ни один объект не должен быть вставлен.


person ulejon    schedule 07.07.2015    source источник


Ответы (2)


Согласно документации, вы можете используйте .transactionally в db-действии:

val a = (for {
  ns <- coffees.filter(_.name.startsWith("ESPRESSO")).map(_.name).result
  _ <- DBIO.seq(ns.map(n => coffees.filter(_.name === n).delete): _*)
} yield ()).transactionally

val f: Future[Unit] = db.run(a)

Что приводит к следующему примеру для предоставленного вами кода:

val a = (for (id <- ids){
   someTable.insert(SomeObject(id))
} yield ()).transactionally

val f: Future[Unit] = db.run(a)
person Peanut    schedule 07.07.2015
comment
Это не работает. Похоже, функция insert больше не существует. Я пытался заменить его на +=, но это тоже не работает. - person ulejon; 07.07.2015
comment
Немного поигравшись, я придумал следующее: val toInsert = for (id <- ids) yield SomeObject(id) val insertActions = DBIO.seq(someTable ++= toInsert.toSeq).transactionally val f: Future[Unit] = db.run(insertActions) Не уверен, что это лучший способ сделать это? - person ulejon; 07.07.2015

У меня был немного другой сценарий, когда мне нужно было обновить две таблицы в одной транзакции, следующий код кажется наиболее элегантным способом добиться этого:

val c: DBIOAction[(Int, Int), NoStream, Effect.Write with Effect.Write] = for{
      i1 <- (tbl1 += record1)
      i2 <- (tbl2 += record2)
    } yield {
      (i1,i2)
    }
val f = db run c.transactionally

Глядя на это, я понял, что это похоже на scala Future api, поэтому должен быть метод последовательности, и он действительно есть:

val actions = Seq((tbl1 += record1), (tbl2 += record2))
val dbActions: DBIOAction[Seq[Int], NoStream, Effect.Write with Effect.Transactional]
    =  DBIOAction.sequence(actions).transactionally
val f = db run dbActions

в исходном варианте использования вы можете просто создавать действия с помощью for-comprehension.

person Eyal Farago    schedule 28.03.2018