Reputation: 641
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
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
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