Scala Slick - 在 table 中插入并省略一些列并返回新行的主键
Scala Slick - Insert in table with omitting some columns and returning primary key of new line
对于 scala 项目,我使用 play-slick
和 play-slick-evolutions
两个版本 5.0.0
并且我生成我的数据库 classes 和 slick-codegen
版本3.3.3
.
我有一个带有 primary key
列的 table 和带有 default values
的一些列。我想插入一行而不提及主键列或任何具有默认值的列。理想情况下,此操作应该 return 创建行的新主键。
我的问题是 slick-codegen
生成的代码似乎只允许插入完整的行,因为它对行使用了自己的案例 class。这是生成的代码的样子(没有注释):
case class SalesOrderRow(idSalesOrder: Int, fkCustomer: Int, createdAt: java.sql.Timestamp, createdBy: Option[String] = None)
implicit def GetResultSalesOrderRow(implicit e0: GR[Int], e1: GR[java.sql.Timestamp], e2: GR[Option[String]]): GR[SalesOrderRow] = GR{
prs => import prs._
SalesOrderRow.tupled((<<[Int], <<[Int], <<[java.sql.Timestamp], <<?[String]))
}
class SalesOrder(_tableTag: Tag) extends profile.api.Table[SalesOrderRow](_tableTag, Some("test"), "sales_order") {
def * = (idSalesOrder, fkCustomer, createdAt, createdBy) <> (SalesOrderRow.tupled, SalesOrderRow.unapply)
def ? = ((Rep.Some(idSalesOrder), Rep.Some(fkCustomer), Rep.Some(createdAt), createdBy)).shaped.<>({r=>import r._; _1.map(_=> SalesOrderRow.tupled((_1.get, _2.get, _3.get, _4)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported."))
val idSalesOrder: Rep[Int] = column[Int]("id_sales_order", O.AutoInc, O.PrimaryKey)
val fkCustomer: Rep[Int] = column[Int]("fk_customer")
val createdAt: Rep[java.sql.Timestamp] = column[java.sql.Timestamp]("created_at")
val createdBy: Rep[Option[String]] = column[Option[String]]("created_by", O.Length(20,varying=true), O.Default(None))
}
lazy val SalesOrder = new TableQuery(tag => new SalesOrder(tag))
有了这个生成的代码,我现在可以插入一行并提及完整的列:
val insertActionsNotSoNice =
DBIO.seq(
salesOrders += Tables.SalesOrderRow(0, 3, new Timestamp(System.currentTimeMillis()), Some("这个不好"))
)
但是我想省略开头的主键和有默认值的时间戳参数。但是不能做这样的事情。
val insertActionsNotCompiling =
DBIO.seq(
salesOrders.map(so => (so.fkCustomer, so.createdBy) += (3, Some("这个好")))
)
我在精巧的文档和网络中发现了很多类似于后一种方法的示例,但通常情况下,它们用于数据库的 classes 确实有一个元组而不是自己的行class。喜欢...
class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES")
而不是
class Coffees(_tableTag: Tag) extends profile.api.Table[CoffeesRow](_tableTag, Some("test"), "coffee")
我是否必须将 slick-codegen
从我的项目中删除并自己编写所有 class 来满足我的需要,或者我的 play-slick
库组合是错误的?或者是否有一个简单的技巧可以在插入未记录的内容时省略列?
经过几天的尝试,我找到了一个解决方案。
您可以将查询映射到 select 您想要插入的列,然后如果您想要 return 插入行的 ID,则使用 returning
。
import dao.Tables.profile.api._
// ...
val salesOrders = TableQuery[SalesOrder]
val insertStatement = salesOrders.map(so => (so.fkCustomer, so.createdBy)) returning salesOrders.map(_.idSalesOrder) into ((_, id) => id)
然后你可以这样写:
val newSalesOrderIdFuture = db.run(insertStatement += (5, Some("有效")))
所以我在插入语句中省略了主键列(id_sales_order
)和数据库中默认为now()
的时间戳列(created_at
)。
对于 scala 项目,我使用 play-slick
和 play-slick-evolutions
两个版本 5.0.0
并且我生成我的数据库 classes 和 slick-codegen
版本3.3.3
.
我有一个带有 primary key
列的 table 和带有 default values
的一些列。我想插入一行而不提及主键列或任何具有默认值的列。理想情况下,此操作应该 return 创建行的新主键。
我的问题是 slick-codegen
生成的代码似乎只允许插入完整的行,因为它对行使用了自己的案例 class。这是生成的代码的样子(没有注释):
case class SalesOrderRow(idSalesOrder: Int, fkCustomer: Int, createdAt: java.sql.Timestamp, createdBy: Option[String] = None)
implicit def GetResultSalesOrderRow(implicit e0: GR[Int], e1: GR[java.sql.Timestamp], e2: GR[Option[String]]): GR[SalesOrderRow] = GR{
prs => import prs._
SalesOrderRow.tupled((<<[Int], <<[Int], <<[java.sql.Timestamp], <<?[String]))
}
class SalesOrder(_tableTag: Tag) extends profile.api.Table[SalesOrderRow](_tableTag, Some("test"), "sales_order") {
def * = (idSalesOrder, fkCustomer, createdAt, createdBy) <> (SalesOrderRow.tupled, SalesOrderRow.unapply)
def ? = ((Rep.Some(idSalesOrder), Rep.Some(fkCustomer), Rep.Some(createdAt), createdBy)).shaped.<>({r=>import r._; _1.map(_=> SalesOrderRow.tupled((_1.get, _2.get, _3.get, _4)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported."))
val idSalesOrder: Rep[Int] = column[Int]("id_sales_order", O.AutoInc, O.PrimaryKey)
val fkCustomer: Rep[Int] = column[Int]("fk_customer")
val createdAt: Rep[java.sql.Timestamp] = column[java.sql.Timestamp]("created_at")
val createdBy: Rep[Option[String]] = column[Option[String]]("created_by", O.Length(20,varying=true), O.Default(None))
}
lazy val SalesOrder = new TableQuery(tag => new SalesOrder(tag))
有了这个生成的代码,我现在可以插入一行并提及完整的列:
val insertActionsNotSoNice =
DBIO.seq(
salesOrders += Tables.SalesOrderRow(0, 3, new Timestamp(System.currentTimeMillis()), Some("这个不好"))
)
但是我想省略开头的主键和有默认值的时间戳参数。但是不能做这样的事情。
val insertActionsNotCompiling =
DBIO.seq(
salesOrders.map(so => (so.fkCustomer, so.createdBy) += (3, Some("这个好")))
)
我在精巧的文档和网络中发现了很多类似于后一种方法的示例,但通常情况下,它们用于数据库的 classes 确实有一个元组而不是自己的行class。喜欢...
class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES")
而不是
class Coffees(_tableTag: Tag) extends profile.api.Table[CoffeesRow](_tableTag, Some("test"), "coffee")
我是否必须将 slick-codegen
从我的项目中删除并自己编写所有 class 来满足我的需要,或者我的 play-slick
库组合是错误的?或者是否有一个简单的技巧可以在插入未记录的内容时省略列?
经过几天的尝试,我找到了一个解决方案。
您可以将查询映射到 select 您想要插入的列,然后如果您想要 return 插入行的 ID,则使用 returning
。
import dao.Tables.profile.api._
// ...
val salesOrders = TableQuery[SalesOrder]
val insertStatement = salesOrders.map(so => (so.fkCustomer, so.createdBy)) returning salesOrders.map(_.idSalesOrder) into ((_, id) => id)
然后你可以这样写:
val newSalesOrderIdFuture = db.run(insertStatement += (5, Some("有效")))
所以我在插入语句中省略了主键列(id_sales_order
)和数据库中默认为now()
的时间戳列(created_at
)。