【Vapor】08 Chapter 9: Parent-Child Relationships

0x00 Chapter 9: Parent-Child Relationships

5.Setting up the relationship

Because a user owns each acronym, you add a user property to the acronym.

a. open Acronym.swift

add a new property after var long: String

    @Parent(key: "userID")
    var user: User

Replace the initializer

    init(id: UUID? = nil, short: String, long: String, userID: User.IDValue) {
        self.id = id
        self.short = short
        self.long = long
        self.$user.id = userID
    }

b. open CreateAcronym.swift

Before .create() add the following line

    .field("userID", .uuid, .required)

c. open AcronymsController.swift

add the following code At the bottom of file

struct CreateAcronymData: Content {
    let short: String
    let long: String
    let userID: UUID
}

update the body of createHandler(_:) :

    func createHandler(_ req: Request) throws -> EventLoopFuture<Acronym> {
        //let acronym = try req.content.decode(Acronym.self)
        let data = try req.content.decode(CreateAcronymData.self)
        let acronym = Acronym(short: data.short, long: data.long, userID: data.userID)
        return acronym.save(on: req.db).map { acronym }
    }

update the body of updateHandler(_:) :

    func updateHandler(_ req: Request) throws -> EventLoopFuture<Acronym> {
        //let updatedAcronym = try req.content.decode(Acronym.self)
        let updateData = try req.content.decode(CreateAcronymData.self)
        return Acronym.find(req.parameters.get("acronymID"), on: req.db)
            .unwrap(or: Abort(.notFound)).flatMap { acronym in
                acronym.short = updateData.short
                acronym.long = updateData.long
                acronym.$user.id = updateData.userID
                return acronym.save(on: req.db).map {
                    acronym
                }
            }
    }

6.reset the database

To add the new column to the table, you must delete the database so Fluent will run the migration again.

如果数据库在运行,先停止
打开终端:
docker stop postgres

删除数据库:
docker rm postgres

重新创建数据库:

docker run --name postgres \
-e POSTGRES_DB=vapor_database \
-e POSTGRES_USER=vapor_username \
-e POSTGRES_PASSWORD=vapor_password \
-p 5432:5432 \
-d postgres

因为数据库被删除了
所以数据需要重新生成
参考前面几遍文章

提交 acronym 数据:

url: http://127.0.0.1:8080/api/acronyms
method: POST
parameters: {"short": "MMD", "long":"么么哒","userID":"A1B2C3D4"}

userID 是随便写的
后面加了外键约束后,就不能随便写了


提交 user 数据:
url: http://127.0.0.1:8080/api/users
method: POST
parameters: {"name": "老三", "username":"张三"}


7.Querying the relationship

Getting the parent

open AcronymsController.swift
add a new route handler after sortedHandler(_:):

    func getUserHandler(_ req: Request) throws -> EventLoopFuture<User> {
        Acronym.find(req.parameters.get("acronymID"), on: req.db)
            .unwrap(or: Abort(.notFound))
            .flatMap { acronym in
                acronym.$user.get(on: req.db)
            }
    }

Register the route handler at the end of boot(routes:)

    acronymsRoutes.get(":acronymID", "user", use: getUserHandler)

根据 acronymID 查询 user
url: http://127.0.0.1:8080/api/acronyms/F3320C03-8570-443F-A8AB-071681470DA4/user
method: GET
parameters:

通过浏览器直接访问
返回数据,格式化后:

{
    "id": "0DFD7B3A-F38D-43AA-8DD5-26B71E4FE3D0",
    "username": "张三",
    "name": "老三"
}

Getting the children

open User.swift
add a new property below var username: String

    @Children(for: \.$user)
    var acronyms: [Acronym]

open UsersController.swift
add a new route handler after getHandler(_:):

    func getAcronymsHandler(_ req: Request) throws -> EventLoopFuture<[Acronym]> {
        User.find(req.parameters.get("userID"), on: req.db)
            .unwrap(or: Abort(.notFound))
            .flatMap { user in
                user.$acronyms.get(on: req.db)
            }
    }

Register the route handler at the end of boot(routes:):

usersRoute.get(":userID", "acronyms", use: getAcronymsHandler)

根据 userID 查询 acronym
url: http://127.0.0.1:8080/api/users/0DFD7B3A-F38D-43AA-8DD5-26B71E4FE3D0/acronyms
method: GET
parameters:

通过浏览器直接访问
返回数据:

[
    {
        "id": "F3320C03-8570-443F-A8AB-071681470DA4",
        "short": "MMD",
        "long": "么么哒",
        "user": {
            "id": "0DFD7B3A-F38D-43AA-8DD5-26B71E4FE3D0"
        }
    }
]

8.Foreign key constraints

外键约束

describe a link between two tables

Using foreign key constraints has a number of benefits:

  • It ensures you can’t create acronyms with users that don’t exist

  • You can’t delete users until you’ve deleted all their acronyms.

  • You can’t delete the user table until you’ve deleted the acronym table.


9.Foreign key constraints are set up in the migration.

Open CreateAcronym.swift,
and replace .field("userID", .uuid, .required) with the following

.field("userID", .uuid, .required, .references("users", "id"))

Finally, because you’re linking the acronym’s userID property to the User table
you must create the User table first
In configure.swift, move the User migration to before the Acronym migration:

    app.migrations.add(CreateUser())
    app.migrations.add(CreateAcronym())

最后再重新操作一遍:
停止数据库:
docker stop postgres

删除数据库:
docker rm postgres

重新创建数据库:

docker run --name postgres \
-e POSTGRES_DB=vapor_database \
-e POSTGRES_USER=vapor_username \
-e POSTGRES_PASSWORD=vapor_password \
-p 5432:5432 \
-d postgres

提交 acronym 时,如果 userID 随便写
比如把 userID 最后一位改一下
会导致错误:
violates foreign key constraint
违反外键约束

{
    "error": true,
    "reason": "server: insert or update on table \"acronyms\" violates foreign key constraint \"acronyms_userID_fkey\" (ri_ReportViolation)"
}

请添加图片描述


0x01 我的作品

欢迎体验我的作品之一:小五笔小程序
学习五笔,好帮手!
微信搜索 XWubi 即可~


猜你喜欢

转载自blog.csdn.net/xjh093/article/details/124199095