1

I'm in the middle of upgrading my Play Framework application using slick 2.1.0 to play-slick 1.0.0 (which includes slick 3.0.0).

I'm having some problems understanding how transactions are handled.

Lets say I have the following piece of code:

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

How do I do that in slick 3? I want all the objects to be inserted in one transaction. If one object fails to be inserted, none should be inserted.

ulejon
  • 631
  • 5
  • 22

2 Answers2

1

According to the documentation, you can use .transactionally on a db-action:

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)

Which yields to the following example for your provided code:

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

val f: Future[Unit] = db.run(a)
Peanut
  • 3,753
  • 3
  • 31
  • 45
  • That does not work. Doesn't seem like the function `insert` exists any more. I tried to replace it with `+=`, but that does not work either. – ulejon Jul 07 '15 at 18:01
  • After some playing around I came up with this: `val toInsert = for (id <- ids) yield SomeObject(id)` `val insertActions = DBIO.seq(someTable ++= toInsert.toSeq).transactionally` `val f: Future[Unit] = db.run(insertActions)` Not sure if that is the best way to do it? – ulejon Jul 07 '15 at 18:14
0

I had a slightly different scenario where I had to update two tables in the same transaction, the following code seems to be the most elegant way to achieve this:

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

looking at this, it hit me this resembles scala Future's api, so there must be a sequence method, and indeed there is one:

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

in the original use case, you can simply construct actions with your for-comprehension.