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 thatdon’t
exist -
You
can’t
delete users until you’vedeleted
all their acronyms. -
You
can’t
delete the user table until you’vedeleted
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
即可~