【问题标题】:How do I update the children in a one-to-many relationship in Vapor 4/FluentKit?如何在 Vapor 4/FluentKit 中更新一对多关系中的孩子?
【发布时间】:2021-03-19 20:58:39
【问题描述】:

我已经梳理了文档here,但我不太清楚如何更新关系和模型(例如,关系发生了变化,属性发生了变化)。解码后 ModelA 中的“childrenArray”似乎为空,但是,我无法确定,因为在尝试打印值时出现此错误:

致命错误:子关系未急切加载,使用 $ 前缀访问

我的父模型:

final class ModelA: Model, Content {
    static let schema = "model_a"
    
    // MARK: - PROPERTIES
    
    @ID(key: .id)
    var id: UUID?

    @Field(key: "name")
    var name: String
    
    // MARK: - RELATIONS
    
    @Children(for: \.$modelA)
    var childrenArray: [ModelB]

    init() { }

    init(id: UUID? = nil, name: String) {
        self.id = id
        self.name = name
    }
}

儿童模型:

final class ModelB: Model, Content {
    static let schema = "model_b"

    // MARK: - Properties
    
    @ID(key: .id)
    var id: UUID?

    @Field(key: "command")
    var command: String
    
    // MARK: - Relations
    
    @Parent(key: "model_a_id")
    var modelA: ModelA
}

我的更新功能:

func update(req: Request) throws -> EventLoopFuture<ModelA> {
        guard let id = req.parameters.get("id", as: UUID.self) else {
            throw Abort(.internalServerError)
        }
        
        let updatedModelA = try req.content.decode(ModelA.self)
        return ModelA.find(id, on: req.db)
            .unwrap(or: Abort(.notFound))
            .flatMap { modelA in
                modelA.$childrenArray.create(updatedModelA.childrenArray, on: req.db)
                return modelA.update(on: req.db).map { modelA }
            }
    }

作为参考,Postman POST 请求如下所示:

{
    "id": "<ModelA's UUID>",
    "name": "ModelA Name",
    "childrenArray": [{
        "id": "{{$randomUUID}}" ,
        "command": ""
    }]
}

【问题讨论】:

    标签: vapor vapor-fluent


    【解决方案1】:

    要完成“急切加载”,您需要在父查询中包含with。您不能使用 find 执行此操作,因此您需要将查询更改为:

    ModelA.query(on: req.db)
        .filter(\.$id == id)
        .with(\.$childrenArray)
        .first()
        .unwrap(or: Abort(.notFound))
        .flatMap { modelA in
            // can access children now
            return modelA.update(on: req.db).map { modelA }
        }
    

    我假设您希望此行在 ModelB 中创建子代:

    modelA.$childrenArray.create(updatedModelA.childrenArray, on: req.db)
    

    不会的。您需要创建ModelB 的新实例,初始化父属性,然后调用create

    【讨论】:

    • 谢谢尼克,我能做到。看起来还有一种方法可以保存我可以在这种情况下使用的模型数组docs.vapor.codes/4.0/fluent/model/#create。最后一个问题,为了做你提到的事情,我需要知道 - 在这一行之后访问孩子时,我仍然遇到“急切负载”错误:let updatedModelA = try req.content.decode(ModelA.self) 它只是在解码请求,所以有此时没有数据库查询。如何访问该对象的childrenArray?我是否必须解码为不扩展 Model 的数据模型?
    • 对不起,直到现在才看到你的评论。使用专用的 Decodable 结构,其中仅包含您想要从请求中获取的字段,而不是 ModelA 本身。
    猜你喜欢
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 2018-11-13
    • 1970-01-01
    • 2012-02-08
    • 2014-03-12
    相关资源
    最近更新 更多