0x00 Chapter 10 Sibling Relationships
1.Sibling relationships describe a relationship that links two models to each other They are also known as many-to-many relationships
Unlike parent-child relationships, there are no constraints between models in a sibling relationship
For instance, if you model the relationship between pets and toys a pet can have one or more toys and a toy can be used by one or more pets
In the TIL application, you’ll be able to categorize acronyms. An acronym can be part of one or more categories and a category can contain one or more acronyms
2.Category model create a new file Category.swift in Sources/App/Models
import Vapor
import Fluent
final class Category: Model, Content {
static let schema = "categories"
@ID
var id: UUID?
@Field(key: "name")
var name: String
init() {}
init(id: UUID? = nil, name: String) {
self.id = id
self.name = name
}
}
3.Migration create a new file CreateCategory.swift in Sources/App/Migrations
import Fluent
struct CreateCategory: Migration {
func prepare(on database: Database) -> EventLoopFuture
database.schema("categories")
.id()
.field("name", .string, .required)
.create()
}
func revert(on database: Database) -> EventLoopFuture
database.schema("categories").delete()
}
}
open configure.swift and add CreateCategory to the migration list, after app.migrations.add(CreateAcronym())
app.migrations.add(CreateCategory())
4.Category controller create a new file called CategoriesController.swift In Sources/App/Controllers
import Fluent
import Vapor
struct CategoriesController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
let categoriesRoute = routes.grouped("api", "categories")
categoriesRoute.post(use: createHandler)
categoriesRoute.get(use: getAllHandler)
categoriesRoute.get(":categoryID", use: getHandler)
categoriesRoute.get(":categoryID", "acronyms", use: getAcronymsHandler)
}
func createHandler(_ req: Request) throws -> EventLoopFuture
let category = try req.content.decode(Category.self)
return category.save(on: req.db).map { category }
}
func getAllHandler(_ req: Request) throws -> EventLoopFuture<[Category]> {
Category.query(on: req.db).all()
}
//
func getHandler(_ req: Request) throws -> EventLoopFuture
Category.find(req.parameters.get("categoryID"), on: req.db)
.unwrap(or: Abort(.notFound))
}
// http://127.0.0.1:8080/api/categories/
func getAcronymsHandler(_ req: Request) throws -> EventLoopFuture<[Acronym]> {
Category.find(req.parameters.get("categoryID"), on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { category in
category.$acronyms.get(on: req.db)
}
}
}
open routes.swift and register the controller by adding the following to the end of routes(_:)
app.migrations.add(CreateCategory())
通过 Rested 提交 category 数据 url:http://127.0.0.1:8080/api/categories method:POST parameter:{"name": "Teenager"}
5.Creating a pivot In Chapter 9, “Parent Child Relationships”, you added a reference to the user in the acronym to create the relationship between an acronym and a user
However, you can’t model a sibling relationship like this as it would be too inefficient to query
You need a separate model to hold on to this relationship. In Fluent, this is a pivot
create file called AcronymCategoryPivot.swift in Sources/App/Models
import Vapor
import Fluent
final class AcronymCategoryPivot: Model {
static let schema = "acronym-category-pivot"
@ID
var id: UUID?
@Parent(key: "acronymID")
var acronym: Acronym
@Parent(key: "categoryID")
var category: Category
init() {}
init(id: UUID? = nil, acronym: Acronym, category: Category) throws {
self.id = id
self.$acronym.id = try acronym.requireID()
self.$category.id = try category.requireID()
}
}
Create CreateAcronymCategoryPivot.swift in Sources/App/Migrations
import Fluent
struct CreateAcronymCategoryPivot: Migration {
func prepare(on database: Database) -> EventLoopFuture
database.schema("acronym-category-pivot")
.id()
.field("acronymID", .uuid, .required, .references("acronyms", "id", onDelete: .cascade))
.field("categoryID", .uuid, .required, .references("categories", "id", onDelete: .cascade))
.create()
}
func revert(on database: Database) -> EventLoopFuture
database.schema("acronym-category-pivot").delete()
}
}
As in Chapter 9, “Parent Child Relationships,” it’s good practice to use foreign key constraints with sibling relationships
The migration also sets a cascade schema reference action when you delete the model. This causes the database to remove the relationship automatically instead of throwing an error
open configure.swift and add CreateAcronymCategoryPivot to the migration list, after app.migrations.add(CreateCategory())
app.migrations.add(CreateAcronymCategoryPivot())
0x01 创建关联关系(多对多)
下篇正在准备中… 敬请期待~
0x02 我的作品
欢迎体验我的作品之一:小五笔小程序 五笔学习好帮手! 微信 搜索即可~
参考链接
发表评论