Slick:两次查询,一次交易
Slick: two queries, one transaction
假设我有两个 tables:
people:
id: long | uuid: UUID | name: String
----
cars
id: long | owner_id: long | name: String
其中 owner
是 people.id
的外键。
我有一个查询 select 所有车主的 uuid(只是一个 API 设计)。
问题是:如何在一个事务中执行以下查询,我必须通过其 uuid
(SELECT id from people where uuid = ?
) 获得 people.id
然后 SELECT * from cars where owner_id = id
?
当然,我一开始可以通过它的uuid
从people
table得到id
,比如
val ownerId = db run people.filter(_.uuid === uuid.bind).map(_.id).result.head
然后 运行 对 select 汽车的另一个查询 owner_id
:
val cars = ownerId.flatMap {
id => db run cars.filter(_.ownerId === id).result
}
但这不会在一次交易中发生。有什么想法吗?
我会说:
val groupByQuery = cars.join(people)
.on (_.owner_id === _.id)
.map{
case (car, owner) => (owner.uuid, car)
}
.groupBy(_._1)
db.run(groupByQuery)
有一个 transactionally
的方法来进行巧妙的操作。你应该使用:
import slick.driver.PostgresDriver.api._ // for example
val query = for {
p <- peoples.filter(_.uuid === "some-id")
c <- cars.filter(_.owner_id === p.uuid)
} yield (p, c)
val action = query.result
val transactionalAction = action.transactionally // will be executed
// in single transaction
// Ungrouped result
// TODO: You can group on db side by your query or
// on client side using groupBy from collection API
val result:Future[Seq[(People, Cars)]] = db.run(transactionalAction)
假设我有两个 tables:
people:
id: long | uuid: UUID | name: String
----
cars
id: long | owner_id: long | name: String
其中 owner
是 people.id
的外键。
我有一个查询 select 所有车主的 uuid(只是一个 API 设计)。
问题是:如何在一个事务中执行以下查询,我必须通过其 uuid
(SELECT id from people where uuid = ?
) 获得 people.id
然后 SELECT * from cars where owner_id = id
?
当然,我一开始可以通过它的uuid
从people
table得到id
,比如
val ownerId = db run people.filter(_.uuid === uuid.bind).map(_.id).result.head
然后 运行 对 select 汽车的另一个查询 owner_id
:
val cars = ownerId.flatMap {
id => db run cars.filter(_.ownerId === id).result
}
但这不会在一次交易中发生。有什么想法吗?
我会说:
val groupByQuery = cars.join(people)
.on (_.owner_id === _.id)
.map{
case (car, owner) => (owner.uuid, car)
}
.groupBy(_._1)
db.run(groupByQuery)
有一个 transactionally
的方法来进行巧妙的操作。你应该使用:
import slick.driver.PostgresDriver.api._ // for example
val query = for {
p <- peoples.filter(_.uuid === "some-id")
c <- cars.filter(_.owner_id === p.uuid)
} yield (p, c)
val action = query.result
val transactionalAction = action.transactionally // will be executed
// in single transaction
// Ungrouped result
// TODO: You can group on db side by your query or
// on client side using groupBy from collection API
val result:Future[Seq[(People, Cars)]] = db.run(transactionalAction)