ulejon
ulejon

Reputation: 641

Multiple inserts in same transaction with Slick 3.0

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.

Upvotes: 2

Views: 2631

Answers (2)

Eyal Farago
Eyal Farago

Reputation: 63

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.

Upvotes: 0

Peanut
Peanut

Reputation: 3963

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)

Upvotes: 2

Related Questions