Vapor/Leaf传递数据库数据至Leaf视图触发superEncoder致命错误
LeafEncoder superEncoder致命错误排查与解决
问题原因
你的Cocktail模型包含@Parent关联属性(difficulty_id和glass_id),但查询时未预加载这些关联数据,Leaf编码器尝试对未加载的关联对象编码时触发了致命错误。另外,直接传递完整的Model对象给视图上下文,编码器需要处理Fluent的关联类型,这超出了Leaf默认编码器的处理能力。
解决方法
方法1:预加载关联数据
修改查询逻辑,预加载关联的Difficulty和Glass对象,确保编码器能获取完整的可编码数据:
app.get("dashboard") { req async throws -> View in // 预加载关联的难度和杯型数据 let result = try await Cocktail.query(on: req.db) .with(\.$difficulty_id) .with(\.$glass_id) .all() let context = CocktailContext(cocktails: result) return try await req.view.render("dashboard", context) }
方法2:使用视图专用DTO(推荐)
创建仅包含视图所需字段的结构体,避免传递完整Model对象,降低编码复杂度:
// 新增视图专用数据传输对象 struct CocktailViewData: Codable { let id: UUID? let name: String let description: String let amountMl: Int let imgUrl: String let videoUrl: String? let difficultyId: UUID let glassId: UUID // 从Cocktail模型转换数据 init(from cocktail: Cocktail) { self.id = cocktail.id self.name = cocktail.name self.description = cocktail.description self.amountMl = cocktail.amount_ml self.imgUrl = cocktail.img_url self.videoUrl = cocktail.video_url self.difficultyId = cocktail.$difficulty_id.id self.glassId = cocktail.$glass_id.id } } // 修改上下文结构体 struct CocktailContext: Codable { let cocktails: [CocktailViewData] } // 更新路由逻辑 app.get("dashboard") { req async throws -> View in let result = try await Cocktail.query(on: req.db).all() // 将Model数组转换为视图专用DTO数组 let viewData = result.map(CocktailViewData.init) let context = CocktailContext(cocktails: viewData) return try await req.view.render("dashboard", context) }
额外优化
Cocktail模型无需同时声明Model, Content, Codable,因为Model已通过Content继承了Codable,可简化为:
final class Cocktail: Model, Content { // 原有代码保持不变 }
内容的提问来源于stack exchange,提问作者PsKinggood
相关产品推荐
相关产品推荐

