如何使用 Slick 的 insertOrUpdate return 整行
How to return full row using Slick's insertOrUpdate
我目前正在学习 Play2、Scala 和 Slick 3.1,并且非常熟悉使用 insertOrUpdate 的语法,想知道是否有人可以帮助我。
我想做的是在使用 insertOrUpdate 时 return 整行,包括 auto inc 主键,但我只设法 return updated/inserted 行数.
这是我的 table 定义:
package models
final case class Report(session_id: Option[Long], session_name: String, tester_name: String, date: String, jira_ref: String,
duration: String, environment: String, notes: Option[String])
trait ReportDBTableDefinitions {
import slick.driver.PostgresDriver.api._
class Reports(tag: Tag) extends Table[Report](tag, "REPORTS") {
def session_id = column[Long]("SESSION_ID", O.PrimaryKey, O.AutoInc)
def session_name = column[String]("SESSION_NAME")
def tester_name = column[String]("TESTER_NAME")
def date = column[String]("DATE")
def jira_ref = column[String]("JIRA_REF")
def duration = column[String]("DURATION")
def environment = column[String]("ENVIRONMENT")
def notes = column[Option[String]]("NOTES")
def * = (session_id.?, session_name, tester_name, date, jira_ref, duration, environment, notes) <> (Report.tupled, Report.unapply)
}
lazy val reportsTable = TableQuery[Reports]
}
这是我的 DAO 中与 insertOrUpdate 相关的部分,它工作得很好,但只有 return 行数 updated/inserted:
package models
import com.google.inject.Inject
import play.api.db.slick.DatabaseConfigProvider
import scala.concurrent.Future
class ReportsDAO @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends DAOSlick {
import driver.api._
def save_report(report: Report): Future[Int] = {
dbConfig.db.run(reportsTable.insertOrUpdate(report).transactionally)
}
}
我试过 "returning" 但我无法获得我需要的语法并且不断出现类型不匹配,例如下面的代码无法编译(因为它可能完全错误!)
def save_report(report: Report): Future[Report] = {
dbConfig.db.run(reportsTable.returning(reportsTable).insertOrUpdate(report))
}
感谢任何帮助 - 我是 Scala 和 Slick 的新手,如果我遗漏了一些非常明显的东西,我深表歉意。
你不能 return 整个报告,首先 return Id (returning(reportsTable.map(_.session_id))
) 然后得到整个对象
检查数据库中是否存在报告,如果存在则更新它,如果不存在则继续将报告插入数据库。
注意使用事务
以全部或none方式执行上述操作
def getReportDBIO(id: Long): DBIO[Report] = reportsTable.filter(_.session_id === id).result.head
def save_report(report: Report): Future[Report] = {
val query = reportsTable.filter(_.session_id === report.session_id)
val existsAction = query.exists.result
val insertOrUpdateAction =
(for {
exists <- existsAction
result <- exists match {
case true =>
query.update(report).flatMap {_ => getReportDBIO(report.session_id)}.transactionally
case false => {
val insertAction = reportsTable.returning(reportsTable.map(_.session_id)) += report
val finalAction = insertAction.flatMap( id => getReportDBIO(id)).transactionally //transactionally is important
finalAction
}
}
} yield result).transactionally
dbConfig.db.run(insertOrUpdateAction)
}
相应地更新您的 insertOrUpdate 函数
已解决 - 发布它以防其他任何人尝试做类似的事情:
//will return the new session_id on insert, and None on update
def save_report(report: Report): Future[Option[Long]] = {
val insertQuery = (reportsTable returning reportsTable.map(_.session_id)).insertOrUpdate(report)
dbConfig.db.run(insertQuery)
}
运行良好 - insertOrUpdate 不会返回更新时看起来的任何内容,因此如果我需要在更新操作后获取更新后的数据,我可以 运行 后续查询以使用会话获取信息ID。
您可以 return 整行,但它是一个选项,如文档所述,更新时它将为空,并且将是一个 Some(...) 代表插入的行插入。
所以正确的代码是
def save_report(report: Report): Future[Option[Report]] = {dbConfig.db.run(reportsTable.returning(reportsTable).insertOrUpdate(report))}
我目前正在学习 Play2、Scala 和 Slick 3.1,并且非常熟悉使用 insertOrUpdate 的语法,想知道是否有人可以帮助我。
我想做的是在使用 insertOrUpdate 时 return 整行,包括 auto inc 主键,但我只设法 return updated/inserted 行数.
这是我的 table 定义:
package models
final case class Report(session_id: Option[Long], session_name: String, tester_name: String, date: String, jira_ref: String,
duration: String, environment: String, notes: Option[String])
trait ReportDBTableDefinitions {
import slick.driver.PostgresDriver.api._
class Reports(tag: Tag) extends Table[Report](tag, "REPORTS") {
def session_id = column[Long]("SESSION_ID", O.PrimaryKey, O.AutoInc)
def session_name = column[String]("SESSION_NAME")
def tester_name = column[String]("TESTER_NAME")
def date = column[String]("DATE")
def jira_ref = column[String]("JIRA_REF")
def duration = column[String]("DURATION")
def environment = column[String]("ENVIRONMENT")
def notes = column[Option[String]]("NOTES")
def * = (session_id.?, session_name, tester_name, date, jira_ref, duration, environment, notes) <> (Report.tupled, Report.unapply)
}
lazy val reportsTable = TableQuery[Reports]
}
这是我的 DAO 中与 insertOrUpdate 相关的部分,它工作得很好,但只有 return 行数 updated/inserted:
package models
import com.google.inject.Inject
import play.api.db.slick.DatabaseConfigProvider
import scala.concurrent.Future
class ReportsDAO @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends DAOSlick {
import driver.api._
def save_report(report: Report): Future[Int] = {
dbConfig.db.run(reportsTable.insertOrUpdate(report).transactionally)
}
}
我试过 "returning" 但我无法获得我需要的语法并且不断出现类型不匹配,例如下面的代码无法编译(因为它可能完全错误!)
def save_report(report: Report): Future[Report] = {
dbConfig.db.run(reportsTable.returning(reportsTable).insertOrUpdate(report))
}
感谢任何帮助 - 我是 Scala 和 Slick 的新手,如果我遗漏了一些非常明显的东西,我深表歉意。
你不能 return 整个报告,首先 return Id (returning(reportsTable.map(_.session_id))
) 然后得到整个对象
检查数据库中是否存在报告,如果存在则更新它,如果不存在则继续将报告插入数据库。
注意使用事务
以全部或none方式执行上述操作def getReportDBIO(id: Long): DBIO[Report] = reportsTable.filter(_.session_id === id).result.head
def save_report(report: Report): Future[Report] = {
val query = reportsTable.filter(_.session_id === report.session_id)
val existsAction = query.exists.result
val insertOrUpdateAction =
(for {
exists <- existsAction
result <- exists match {
case true =>
query.update(report).flatMap {_ => getReportDBIO(report.session_id)}.transactionally
case false => {
val insertAction = reportsTable.returning(reportsTable.map(_.session_id)) += report
val finalAction = insertAction.flatMap( id => getReportDBIO(id)).transactionally //transactionally is important
finalAction
}
}
} yield result).transactionally
dbConfig.db.run(insertOrUpdateAction)
}
相应地更新您的 insertOrUpdate 函数
已解决 - 发布它以防其他任何人尝试做类似的事情:
//will return the new session_id on insert, and None on update
def save_report(report: Report): Future[Option[Long]] = {
val insertQuery = (reportsTable returning reportsTable.map(_.session_id)).insertOrUpdate(report)
dbConfig.db.run(insertQuery)
}
运行良好 - insertOrUpdate 不会返回更新时看起来的任何内容,因此如果我需要在更新操作后获取更新后的数据,我可以 运行 后续查询以使用会话获取信息ID。
您可以 return 整行,但它是一个选项,如文档所述,更新时它将为空,并且将是一个 Some(...) 代表插入的行插入。
所以正确的代码是
def save_report(report: Report): Future[Option[Report]] = {dbConfig.db.run(reportsTable.returning(reportsTable).insertOrUpdate(report))}