Vapor中Database Seeding操作Children关系未Eager Loading崩溃如何解决
Vapor Database Seeding 关联属性崩溃解决方案
错误原因
你遇到的崩溃和Eager Loading没有直接关系,Eager Loading是查询数据时用来优化性能、避免N+1查询的特性,本次崩溃的核心是@Children属性的设计限制:@Children是Vapor Fluent专为读取关联数据设计的属性包装器,只读不可直接修改,直接访问不带$前缀的plans属性时,如果没有提前从数据库加载过关联数据,就会触发你看到的崩溃提示。
正确实现方案
1. 填充数据场景的写法(不需要Eager Loading)
新增关联数据时不需要修改City的plans属性,只需要给子模型Plan的关联父属性赋值后保存即可自动建立关联,修改后的填充代码如下:
func prepare(on database: Database) -> EventLoopFuture<Void> { return User.query(on: database).first().flatMap { user -> EventLoopFuture<Void> in guard let userId = user?.id else { return database.eventLoop.makeSucceededVoidFuture() } let cities = [ City(id: UUID(), name: "London", isActive: true, createdAt: Date()), City(id: UUID(), name: "New York", isActive: true, createdAt: Date()), City(id: UUID(), name: "San Francisco", isActive: true, createdAt: Date()), ] let operationFutures = cities.map { city in // 先保存City,确保ID持久化到数据库 return city.save(on: database).flatMap { _ in // 生成关联的Plan数组,createPlans内部已经为每个Plan的cityId赋值 let plans = createPlans(cityId: city.id, userId: userId) // 批量保存所有Plan,自动建立和City的关联 return plans.create(on: database) } } return operationFutures.flatten(on: database.eventLoop) } }
2. 查询场景的Eager Loading正确用法
如果你在查询数据时需要访问City的plans属性,只需要在查询时添加with方法启用Eager Loading即可,示例代码如下:
City.query(on: database) .with(\.$plans) // 此处加$前缀访问关系键路径,启用Eager Loading .all() .whenSuccess { cities in // 此时plans数据已经提前加载完成,直接访问不会崩溃 for city in cities { print("\(city.name) 关联计划数:\(city.plans.count)") } }
内容的提问来源于stack exchange,提问作者KrzysiekS
相关产品推荐
相关产品推荐

