天天看點

【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)      

根據 ​

​acronym​

​​ 的 ​

​ID​

​​ 查詢 ​

​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)      

根據 ​

​user​

​​ 的 ​

​ID​

​​ 查詢 ​

​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)"
}