如何在for推导式中条件执行Slick数据库操作语句?
Slick Conditional Transactional Updates Solution
Got it, let's work through this problem where we only want to run table2 and table3 updates when doUpdate is true, while always executing the table1 update—all wrapped in a transaction to maintain atomicity.
Solution 1: Sequential Action Composition (Clean & Explicit)
This approach separates the mandatory update from the conditional ones, making the logic easy to follow:
val doUpdate = true val table1 = TableQuery[Table1DB] val table2 = TableQuery[Table2DB] val table3 = TableQuery[Table3DB] // Mandatory: always update table1 val updateTable1 = table1.filter(_.id === id).update(table1Record) // Conditional: run table2 + table3 updates only if doUpdate is true; else no-op val conditionalUpdates = if (doUpdate) { for { _ <- table2.filter(_.id === id).update(table2Record) _ <- table3.filter(_.id === id).update(table3Record) } yield () } else { // Slick's no-op action: returns successfully without doing anything DBIO.successful(()) } // Combine all actions in sequence and wrap in a transaction val action = (updateTable1 >> conditionalUpdates).transactionally
Solution 2: Inline Conditional in For Comprehension (Close to Your Original Code)
If you prefer to keep the structure similar to your initial attempt, you can embed the condition directly in the for comprehension:
val doUpdate = true val table1 = TableQuery[Table1DB] val table2 = TableQuery[Table2DB] val table3 = TableQuery[Table3DB] val action = (for { _ <- table1.filter(_.id === id).update(table1Record) // Only run table2 update if doUpdate is true; else no-op _ <- if (doUpdate) table2.filter(_.id === id).update(table2Record) else DBIO.successful(()) // Same logic for table3 _ <- if (doUpdate) table3.filter(_.id === id).update(table3Record) else DBIO.successful(()) } yield ()).transactionally
Key Notes
- DBIO No-Op: We use
DBIO.successful(())for the false branch because every step in a Slick DBIO sequence/for comprehension must return aDBIOtype. This ensures the entire chain remains valid regardless ofdoUpdate's value. - Transactional Safety: The
.transactionallymodifier still applies to all actions, so if any part of the sequence fails (even conditional ones), the entire transaction rolls back—including thetable1update. - Readability: Solution 1 is better for separating concerns if you might add more conditional logic later, while Solution 2 is more familiar if you're adapting existing code.
内容的提问来源于stack exchange,提问作者ps0604
相关产品推荐
相关产品推荐

