如何插入一个对象并使用自动增量 ID 在单个 slick 事务中更新同一对象
How do I insert an object and use the auto-increment id to update the same object in a single slick transaction
我有以下形式的架构:
CREATE TABLE definitions (
id BIGINT(20) AUTO_INCREMENT PRIMARY KEY,
json LONGTEXT NOT NULL
);
json
是我想 return 给客户的,它应该包括自动生成的 id
.
我想在单笔交易中执行以下操作:
- 插入一个新行,其中
json
不包含 id;从插入中获取自增id。
- 更新同一行并将
json
替换为包含 id
. 的新对象
精巧的文档向我展示了如何获取自动增量 ID,但我不知道如何编写 query/insert 以在单个事务中执行这两个操作。
// TableQuery object for my table
class Definitions(driver: RelationalDriver, tag: Tag) extends ... {
import driver.api._
// implicit conversion for Definition
private implicit val definitionToJson =
MappedColumnType.base[Definition, String](
{ definition => definitionToJson(definition) },
{ json => definitionFromJson(json) }
)
def id: slick.lifted.Rep[Long] =
column[Long](
"id",
ColumnOption.PrimaryKey,
ColumnOption.AutoInc
)
def json: slick.lifted.Rep[Definition] =
column[Definition]("json")
override def * = (
id,
json
) <> (DefinitionRow.tupled, DefinitionRow.unapply)
}
class Dao {
// ...
// operation 1: insert row, and get back auto-increment id
// definitions is an instance of above
val op1 = (definitions returning definitions.map(_.id)) += json
// operation 2: find the inserted row and update the object
val op2 = op1.flatMap(insertId =>
definitions.filter(_.id === insertId)
.map(_.json)
.update(updatedJson(insertId))
// run both in a transaction
db.run(op2.transactionally)
}
op2
拒绝编译。
[error] Slick does not know how to map the given types.
[error] Possible causes: T in Table[T] does not match your *
projection. Or you use an unsupported type in a Query
(e.g. scala List).
[error] Required level: slick.lifted.FlatShapeLevel
[error] Source type: slick.lifted.Rep[Definition]
[error] Unpacked type: T
[error] Packed type: G
[error] val op2 = op1.flatMap(autoIncId =>
correlationDefinitionSlick.filter(_.id ===
autoIncId.get).map(_.json).update(json))
老实说,我不明白为什么它不能映射请求的类型。
编辑:我通过在我的 DAO 中重新定义隐式转换来实现上述功能,但我不明白为什么我需要这样做。
Slick Queries require implicit mappings in scope
您遇到此编译器错误是因为您将 table 中的隐式定义映射声明为私有的,并且无法访问以查询您使用定义的位置。
将您的代码移至容器 class 并在 Table
之外声明隐式平滑映射
class Container(driver: RelationalDriver) {
import driver.api._
// implicit conversion for Definition
private implicit val definitionToJson =
MappedColumnType.base[Definition, String](
{ definition => definitionToJson(definition) },
{ json => definitionFromJson(json) }
)
class Definitions(driver: RelationalDriver, tag: Tag) extends ... {
def id: slick.lifted.Rep[Long] =
column[Long](
"id",
ColumnOption.PrimaryKey,
ColumnOption.AutoInc
)
def json: slick.lifted.Rep[Definition] =
column[Definition]("json")
override def * = (
id,
json
) <> (DefinitionRow.tupled, DefinitionRow.unapply)
}
class Dao {
// ...
// operation 1: insert row, and get back auto-increment id
// definitions is an instance of above
val op1 = (definitions returning definitions.map(_.id)) += json
// operation 2: find the inserted row and update the object
val op2 = op1.flatMap(insertId =>
definitions.filter(_.id === insertId)
.map(_.json)
.update(updatedJson(insertId))
// run both in a transaction
db.run(op2.transactionally)
}
}
我有以下形式的架构:
CREATE TABLE definitions (
id BIGINT(20) AUTO_INCREMENT PRIMARY KEY,
json LONGTEXT NOT NULL
);
json
是我想 return 给客户的,它应该包括自动生成的 id
.
我想在单笔交易中执行以下操作:
- 插入一个新行,其中
json
不包含 id;从插入中获取自增id。 - 更新同一行并将
json
替换为包含id
. 的新对象
精巧的文档向我展示了如何获取自动增量 ID,但我不知道如何编写 query/insert 以在单个事务中执行这两个操作。
// TableQuery object for my table
class Definitions(driver: RelationalDriver, tag: Tag) extends ... {
import driver.api._
// implicit conversion for Definition
private implicit val definitionToJson =
MappedColumnType.base[Definition, String](
{ definition => definitionToJson(definition) },
{ json => definitionFromJson(json) }
)
def id: slick.lifted.Rep[Long] =
column[Long](
"id",
ColumnOption.PrimaryKey,
ColumnOption.AutoInc
)
def json: slick.lifted.Rep[Definition] =
column[Definition]("json")
override def * = (
id,
json
) <> (DefinitionRow.tupled, DefinitionRow.unapply)
}
class Dao {
// ...
// operation 1: insert row, and get back auto-increment id
// definitions is an instance of above
val op1 = (definitions returning definitions.map(_.id)) += json
// operation 2: find the inserted row and update the object
val op2 = op1.flatMap(insertId =>
definitions.filter(_.id === insertId)
.map(_.json)
.update(updatedJson(insertId))
// run both in a transaction
db.run(op2.transactionally)
}
op2
拒绝编译。
[error] Slick does not know how to map the given types.
[error] Possible causes: T in Table[T] does not match your *
projection. Or you use an unsupported type in a Query
(e.g. scala List).
[error] Required level: slick.lifted.FlatShapeLevel
[error] Source type: slick.lifted.Rep[Definition]
[error] Unpacked type: T
[error] Packed type: G
[error] val op2 = op1.flatMap(autoIncId =>
correlationDefinitionSlick.filter(_.id ===
autoIncId.get).map(_.json).update(json))
老实说,我不明白为什么它不能映射请求的类型。
编辑:我通过在我的 DAO 中重新定义隐式转换来实现上述功能,但我不明白为什么我需要这样做。
Slick Queries require implicit mappings in scope
您遇到此编译器错误是因为您将 table 中的隐式定义映射声明为私有的,并且无法访问以查询您使用定义的位置。
将您的代码移至容器 class 并在 Table
之外声明隐式平滑映射class Container(driver: RelationalDriver) {
import driver.api._
// implicit conversion for Definition
private implicit val definitionToJson =
MappedColumnType.base[Definition, String](
{ definition => definitionToJson(definition) },
{ json => definitionFromJson(json) }
)
class Definitions(driver: RelationalDriver, tag: Tag) extends ... {
def id: slick.lifted.Rep[Long] =
column[Long](
"id",
ColumnOption.PrimaryKey,
ColumnOption.AutoInc
)
def json: slick.lifted.Rep[Definition] =
column[Definition]("json")
override def * = (
id,
json
) <> (DefinitionRow.tupled, DefinitionRow.unapply)
}
class Dao {
// ...
// operation 1: insert row, and get back auto-increment id
// definitions is an instance of above
val op1 = (definitions returning definitions.map(_.id)) += json
// operation 2: find the inserted row and update the object
val op2 = op1.flatMap(insertId =>
definitions.filter(_.id === insertId)
.map(_.json)
.update(updatedJson(insertId))
// run both in a transaction
db.run(op2.transactionally)
}
}