在 Vapor 应用程序中使用 Fluent 进行连接
Doing joins with Fluent in a Vapor application
我正在努力弄清楚如何使用流利的方式将我的两个表连接在一起。本质上我想 运行 这个 SQL 命令:
SELECT p.name, o.amount, o.amount * p.amount total
FROM "OrderPoints" o
INNER JOIN "Points" p ON o.points_id = p.id
WHERE order_id = 10831
我的两个模型设置如下:
final class OrderPoint: Codable, PostgreSQLModel, Content, Migration {
var id: Int? = nil
var orderID: Order.ID
var pointID: Point.ID
var amount: Double = 0
var point: Parent<OrderPoint, Point> {
return parent(\.pointID)
}
}
final class Point: Codable, PostgreSQLModel, Content, Migration {
var id: Int? = nil
var name: String
var abbrev: String
var amount: Double
}
所以现在在我的控制器中我遍历了我关心的所有命令:
// SELECT * FROM orders WHERE "month" = '2018-05-01'
let orders = try Order.query(on: req).filter(\Order.month == month).all()
return orders.flatMap(to: View.self) { orders in
let content = try orders.map { (order) -> OrderIndexContent in
let values = try order.orderPoints.query(on: req).all()
我认为这让我得到了 order_points
中当前 ID 的所有项目,但我只是不知道如何将它与 Points
模型结合起来,以便我可以完成剩下的工作查询的(即获得乘数和点名称)
- 一个
Order
有多个 OrderPoint
项。
- 一个
OrderPoint
有一个单Point
项。
- 一个
Point
可以指向许多 OrderPoint
项。
所以在我认为流利的指代事物的方式中,OrderPoints
不是 一个支点,因为它不是多对多。
这不可能是对的。
以下似乎有效,但不可能是 "right" 方法,因为这会产生大量额外的 SQL 调用,对吗?
_ = try! order.orderPoints
.query(on: req)
.all()
.map(to: Void.self) { pointsForOrder in
pointsForOrder.forEach { orderPoint in
_ = try! orderPoint.point.get(on: req).map(to: Void.self) {
print("\(order.id!) \(order.name) \([=13=].abbrev) \(orderPoint.pointID) = \(orderPoint.amount) = \([=13=].amount * orderPoint.amount)")
}
}
}
为了从 Order
中检索 OrderPoint
中引用的所有 Point
,您必须查询 Point
并加入 OrderPoint
在上面。然后可以在OrderPoint
上添加过滤器过滤你要查询的订单
这将导致以下 Fluent 查询:
Point.query(on: req)
.join(field: \OrderPoint.pointID)
.filter(OrderPoint.self, \OrderPoint.orderID == order.id!)
.all()
然而,这个查询只会 return 一个 Point
的数组,所以你会错过来自 OrderPoint
的信息,正如你在我们关于 Discord 的讨论中指出的那样,我们也会有解码 OrderPoint
,幸运的是 Fluent 有一个很好的方法:.alsoDecode
。所以最终的查询看起来像这样:
Point.query(on: req)
.join(field: \OrderPoint.pointID)
.filter(OrderPoint.self, \OrderPoint.orderID == order.id!)
.alsoDecode(OrderPoint.self)
.all()
这将 return 包含 Point
和 OrderPoint
的元组
我正在努力弄清楚如何使用流利的方式将我的两个表连接在一起。本质上我想 运行 这个 SQL 命令:
SELECT p.name, o.amount, o.amount * p.amount total
FROM "OrderPoints" o
INNER JOIN "Points" p ON o.points_id = p.id
WHERE order_id = 10831
我的两个模型设置如下:
final class OrderPoint: Codable, PostgreSQLModel, Content, Migration {
var id: Int? = nil
var orderID: Order.ID
var pointID: Point.ID
var amount: Double = 0
var point: Parent<OrderPoint, Point> {
return parent(\.pointID)
}
}
final class Point: Codable, PostgreSQLModel, Content, Migration {
var id: Int? = nil
var name: String
var abbrev: String
var amount: Double
}
所以现在在我的控制器中我遍历了我关心的所有命令:
// SELECT * FROM orders WHERE "month" = '2018-05-01'
let orders = try Order.query(on: req).filter(\Order.month == month).all()
return orders.flatMap(to: View.self) { orders in
let content = try orders.map { (order) -> OrderIndexContent in
let values = try order.orderPoints.query(on: req).all()
我认为这让我得到了 order_points
中当前 ID 的所有项目,但我只是不知道如何将它与 Points
模型结合起来,以便我可以完成剩下的工作查询的(即获得乘数和点名称)
- 一个
Order
有多个OrderPoint
项。 - 一个
OrderPoint
有一个单Point
项。 - 一个
Point
可以指向许多OrderPoint
项。
所以在我认为流利的指代事物的方式中,OrderPoints
不是 一个支点,因为它不是多对多。
这不可能是对的。
以下似乎有效,但不可能是 "right" 方法,因为这会产生大量额外的 SQL 调用,对吗?
_ = try! order.orderPoints
.query(on: req)
.all()
.map(to: Void.self) { pointsForOrder in
pointsForOrder.forEach { orderPoint in
_ = try! orderPoint.point.get(on: req).map(to: Void.self) {
print("\(order.id!) \(order.name) \([=13=].abbrev) \(orderPoint.pointID) = \(orderPoint.amount) = \([=13=].amount * orderPoint.amount)")
}
}
}
为了从 Order
中检索 OrderPoint
中引用的所有 Point
,您必须查询 Point
并加入 OrderPoint
在上面。然后可以在OrderPoint
上添加过滤器过滤你要查询的订单
这将导致以下 Fluent 查询:
Point.query(on: req)
.join(field: \OrderPoint.pointID)
.filter(OrderPoint.self, \OrderPoint.orderID == order.id!)
.all()
然而,这个查询只会 return 一个 Point
的数组,所以你会错过来自 OrderPoint
的信息,正如你在我们关于 Discord 的讨论中指出的那样,我们也会有解码 OrderPoint
,幸运的是 Fluent 有一个很好的方法:.alsoDecode
。所以最终的查询看起来像这样:
Point.query(on: req)
.join(field: \OrderPoint.pointID)
.filter(OrderPoint.self, \OrderPoint.orderID == order.id!)
.alsoDecode(OrderPoint.self)
.all()
这将 return 包含 Point
和 OrderPoint