在 Vapor 应用程序中使用 Fluent 进行连接

2024-05-04

我正在努力弄清楚如何使用 Fluent 将两个表连接在一起。本质上我想运行这个 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模型,以便我可以完成其余的查询(即获取相乘的金额和点名称)

  • An Order有多个OrderPoint项目。
  • An OrderPoint has a single Point item.
  • A Point可以指出很多OrderPoint items.

所以我认为流利指的是事物,OrderPoints is not一个枢轴,因为它不是多对多。

这不可能是正确的。

下面的方法似乎有效,但这不可能是“正确”的方法,因为这会产生大量额外的 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) \($0.abbrev) \(orderPoint.pointID) = \(orderPoint.amount) = \($0.amount * orderPoint.amount)")
                      }
                  }
          }

为了检索所有Point中引用的OrderPoint是从Order你必须查询Point并加入OrderPoint在上面。然后你可以添加一个过滤器OrderPoint过滤您要查询的订单。

这将导致以下 Fluent 查询:

Point.query(on: req)
    .join(field: \OrderPoint.pointID)
    .filter(OrderPoint.self, \OrderPoint.orderID == order.id!)
    .all()

然而,这个查询只会返回一个数组Points,所以你会错过来自OrderPoint正如您在我们关于 Discord 的讨论中指出的那样,我们还必须解码OrderPoint,幸运的是 Fluent 有一个很好的方法:.alsoDecode。所以最终的查询将如下所示:

Point.query(on: req)
    .join(field: \OrderPoint.pointID)
    .filter(OrderPoint.self, \OrderPoint.orderID == order.id!)
    .alsoDecode(OrderPoint.self)
    .all()

这将返回一个包含两者的元组Point and OrderPoint

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Vapor 应用程序中使用 Fluent 进行连接 的相关文章

随机推荐