You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift Vapor Fluent如何查询两层关联获取Translation数据?

问题:Vapor 4中关联查询无法获取嵌套关联的Translation数据

我正在使用Vapor 4,数据库结构为:City关联POI,POI关联Translation。我尝试使用join语句查询,期望在City模型中获取Translation数据,但执行以下查询后,尽管数据库存在对应值且POI不为空,却无法获取nameTranslation的值。我想要类似.with(\.$poi.$nameTranslation)的写法,但这无法实现,请问我遗漏了什么?

模型定义

public final class City: Model {
    public static let schema = "cities"

    @ID(custom: "id")
    public var id: Int?
    @Parent(key: "poi_id")
    public var poi: POI
}

public final class POI: Model {
    public static let schema = "b_pois"

    @ID(custom: "id")
    public var id: Int?
    @OptionalParent(key: "name_translation_id")
    public var nameTranslation: Translation?
}

public final class Translation: Model {
    public static let schema = "b_translations"

    @ID(custom: "id")
    public var id: Int?

    @Field(key: "english")
    public var english: String

    @OptionalField(key: "german")
    public var german: String?
    ...
}

原查询代码

let cities = try await City.query(on: dataBase)
            .join(POI.self, on: \POI.$id == \City.$poi.$id)
            .join(Translation.self, on: \POI.$nameTranslation.$id == \Translation.$id)
            .with(\.$poi)
            .filter(City.self, \.$population >= population)
            .all()
// 预期:
cities.first!.poi.nameTranslation != nil
// 或
cities.first!.$poi.$nameTranslation.value != nil

解决方案

Vapor 4的查询构建器不支持直接链式写\.$poi.$nameTranslation来预加载嵌套关联,且手动添加JOIN语句不会自动填充模型的关联属性。要获取嵌套的Translation数据,需要通过嵌套预加载的方式处理:

正确查询写法1(闭包嵌套预加载)

let cities = try await City.query(on: dataBase)
    .with(\.$poi) { poiQuery in
        // 在POI的查询中预加载它的nameTranslation
        poiQuery.with(\.$nameTranslation)
    }
    .filter(City.self, \.$population >= population)
    .all()

正确查询写法2(Vapor 4.50+支持的数组链式预加载)

let cities = try await City.query(on: dataBase)
    .with([\.$poi, \.$poi.$nameTranslation])
    .filter(City.self, \.$population >= population)
    .all()

原写法失效原因

  1. 手动JOIN仅让数据库执行了关联查询,但Vapor模型不会自动将JOIN返回的字段填充到关联属性(如poi.nameTranslation)中,关联属性的填充依赖预加载(.with())逻辑。
  2. 原代码仅预加载了poi,未预加载poi的nameTranslation,因此即使JOIN了Translation表,对应属性仍为nil。

验证

执行正确查询后,即可正常访问嵌套关联数据:

cities.first?.poi.nameTranslation // 不再为nil

内容的提问来源于stack exchange,提问作者Tbi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 09:20:00