ps0604
ps0604

Reputation: 1071

Using transactionally in Slick 3

Usually you would run two or more statements in a transaction. But in all the examples I could find on using transactionally in Slick 3, there's a for comprehension to group these statements, when I usually use the for in a loop.

This works (deleting from two tables in a transaction):

   val action = db.run((for {
      _ <- table1.filter(_.id1 === id).delete
      _ <- table2.filter(_.id2=== id).delete
    } yield ()).transactionally)
    val result = Await.result(action, Duration.Inf)

But is the for/yield needed? is there an alternative way just to run two or more statements in a transaction?

Upvotes: 2

Views: 7015

Answers (2)

Paweł Jurczenko
Paweł Jurczenko

Reputation: 4471

You can use transactionally on every DBIOAction, not just those that are a result of the for comprehension. For example you can use transactionally in combination with the DBIO.seq method, which takes a sequence of actions and runs them sequentially:

val firstAction = table1.filter(_.id === id1).delete
val secondAction = table2.filter(_.id === id2).delete

val combinedAction = DBIO.seq(
  firstAction,
  secondAction
).transactionally

Upvotes: 9

Carlos Vilchez
Carlos Vilchez

Reputation: 2804

For your case for/yield is not the only way to get what you need. But you will have to substitute it for the equivalent representation. The for comprehension is syntactic sugar for a combination of flatMaps and a map. We need to use them because we are using monadic composition to aggregate all the actions in a BDIOAction. So you could also write it as:

val action = db.run(
  table1.filter(_.id1 === id).delete.map ( _ =>
    table2.filter(_.id2=== id).delete
  ).transactionally
)
val result = Await.result(action, Duration.Inf)

The for comprehension is usually used because is more clean, easier to understand and very easy to scale.

Lets have a look at an example with 4 statements in a transactions to see how it looks:

  • This would be with a for comprehension:

    val action = db.run((for {
      _ <- table1.filter(_.id1 === id).delete
      _ <- table2.filter(_.id2=== id).delete
      _ <- table3.filter(_.id3=== id).delete
      _ <- table4.filter(_.id4=== id).delete
    } yield ()).transactionally)
    val result = Await.result(action, Duration.Inf)
    
  • This would be with flatMap/maps:

    val action = db.run(
      table1.filter(_.id1 === id).delete.flatMap ( _ =>
        table2.filter(_.id2 === id).delete.flatMap ( _ =>
          table3.filter(_.id3 === id).delete.map ( _ =>
            table4.filter(_.id4=== id).delete
          )
        )
      ).transactionally
    )
    val result = Await.result(action, Duration.Inf)
    

Upvotes: 7

Related Questions