Slick - 将一行插入到两个与自动递增键链接的表中?

Slick - Inserting a row into two tables linked with an auto-incrementing key?

我是 Slick 的新手,正在努力为以下内容找到一个好的规范示例。

我想在两个 table 中插入一行。第一个 table 有一个自动递增的主键。第二个 table 通过其主键与第一个相关。

所以我想:

  1. 开始交易
  2. 向table1插入一行,生成key
  3. 在table2中插入一行,用上一步生成的外键
  4. 结束事务(如果失败则回滚步骤 2 和 3)

希望能有一个关于上述逻辑的典型示例,以及对下面我的定义的任何相关建议(我对 Slick 还很陌生!)。谢谢!

为 table 1

插入逻辑
private def insertAndReturn(entry: Entry) = 
  entries returning entries.map(_.id) 
  into ((_, newId) => entry.copy(id = newId))

def insert(entry: Entry): Future[Entry] =
  db.run(insertAndReturn(entry) += entry)

(类似于 table 2)

Table 1

class EntryTable(tag: Tag) extends Table[Entry](tag, "tblEntry") {
  def id = column[EntryId]("entryID", O.PrimaryKey, O.AutoInc)
  ... 

  def * = (id, ...).shaped <> (Entry.tupled, Entry.unapply)
}

Table 2

class UsernameChangeTable(tag: Tag) extends Table[UserNameChange](tag, "tblUserNameChange") {
  def entryId = column[EntryId]("entryID")
  ...

  def entry = foreignKey("ENTRY_FK", entryId, entryDao.entries)(
    _.id, onUpdate = Restrict, onDelete = Cascade
  )

我正在使用 MySQL 数据库和 Slick 3.1.0。

你所要做的就是

val tx = 
 insertAndReturn(entry).flatMap { id =>
   insertUserNameChange(UserNameChange(id, ...))
 }.transactionally

db.run(tx)

请注意,insertUserNameChange 是将 UserNameChange 实例插入数据库的函数。它需要您从上一个插入操作返回的 EntryId。

使用 flatMap 组合操作并使用 transactionally 来 运行 事务中的整个查询。

您的 Slick 表格看起来不错。

这是实现此功能的典型示例

package models
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import slick.backend.DatabasePublisher
import slick.driver.H2Driver.api._

case class Supplier1(id:Int,name:String)

class Suppliers1(tag:Tag) extends Table[Supplier1](tag,"SUPPLIERS") {
  def id:Rep[Int] = column[Int]("SUP_ID",O.PrimaryKey,O.AutoInc)
  def name:Rep[String] = column[String]("NAME")

  def * = (id,name) <> 
    (Supplier1.tupled,Supplier1.unapply)
}

case class Coffee1(id:Int,name:String,suppId:Int)

class Coffees1(tag:Tag) extends Table[Coffee1](tag,"COFFEES"){
  def id:Rep[Int] = column[Int]("C_ID",O.PrimaryKey,O.AutoInc)
  def name:Rep[String] = column[String]("COFFEE_NAME")
  def suppId:Rep[Int] = column[Int]("SUP_ID")


  def * = (id,name,suppId) <> (Coffee1.tupled,Coffee1.unapply)

  def supplier = foreignKey("supp_fk", suppId, TableQuery[Suppliers])(_.id)
}

object HelloSlick1 extends App{
val db = Database.forConfig("h2mem1")
val suppliers = TableQuery[Suppliers1]
val coffees = TableQuery[Coffees1]
val setUpF = (suppliers.schema ++ coffees.schema).create
val insertSupplier = suppliers returning suppliers.map(_.id)
//val tx =  (insertSupplier += Supplier1(0,"SUPP 1")).flatMap(id=>(coffees += Coffee1(0,"COF",id))).transactionally
val tx = for{
   supId  <- insertSupplier += Supplier1(0,"SUPP 1")

  cId <- coffees += Coffee1(0,"COF",supId)
} yield ()
tx.transactionally

def exec[T](action: DBIO[T]): T =
    Await.result(db.run(action), Duration.Inf)
exec(setUpF) 
exec(tx)       
exec(suppliers.result.map(println))
exec(coffees.result.map(println))
}