Vapor 4中创建含Fluent ParentProperty的协议出现编译错误如何解决
解决方案
你遇到的编译和运行时错误可以通过直接引用@Parent属性包装器的公开投影值($前缀)解决,不需要访问内部的下划线存储属性,也不需要预加载关联的父模型对象。
正确协议定义
import Fluent import Vapor protocol HasCampaignId: Model { // 要求模型实现@Parent campaign,自动生成的$campaign投影值会匹配该类型要求 var $campaign: ParentProperty<Self, Campaign> { get } func belongsToCampaign(_ campaignID: Campaign.IDValue) throws -> Self } extension HasCampaignId { func belongsToCampaign(_ campaignID: Campaign.IDValue) throws -> Self { // 直接读取当前模型表存储的外键值,无需预加载Campaign对象 guard self.$campaign.id == campaignID else { throw Abort(.forbidden) } return self } }
模型适配示例
只需要给原有模型添加HasCampaignId遵循即可,无需额外代码:
final class Location: Model, Content, HasCampaignId { static let schema = "locations" @ID(key: .id) var id: UUID? @Parent(key: FieldKeys.campaign) var campaign: Campaign // 其他原有属性和初始化方法 init() {} }
原写法报错原因说明
- 第一种访问
_campaign的写法:_campaign是@Parent自动生成的内部存储属性,访问级别受属性本身的控制,容易和协议的访问权限要求冲突,属于非公开的内部实现细节,不建议直接访问。 - 第二种访问
campaign包装值的写法:campaign是属性包装器的包装值,必须提前用with(\.$campaign)预加载关联对象才能访问,否则会触发运行时崩溃,而校验所属关系只需要外键值,完全不需要加载整个父模型。
内容的提问来源于stack exchange,提问作者Kevin Renskers
相关产品推荐
相关产品推荐

