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()
原写法失效原因
- 手动JOIN仅让数据库执行了关联查询,但Vapor模型不会自动将JOIN返回的字段填充到关联属性(如
poi.nameTranslation)中,关联属性的填充依赖预加载(.with())逻辑。 - 原代码仅预加载了
poi,未预加载poi的nameTranslation,因此即使JOIN了Translation表,对应属性仍为nil。
验证
执行正确查询后,即可正常访问嵌套关联数据:
cities.first?.poi.nameTranslation // 不再为nil
内容的提问来源于stack exchange,提问作者Tbi
相关产品推荐
相关产品推荐

