Relations可以让两个数据库通过外键进行关联。这在基础的SQL数据库很常见,但是也可以用于NoSQL的数据库中。
Fluent的Relations有以下几种:
- Parent (BelongsTo)
- Children (HasMany, HasOne)
- Siblings (ManyToMany, BelongsToMany)
Parent
一个实体通过给另一个实体外部键关联起来,就构成了父关系(parent)。如下所示:
pets
- id
- owner_id
- name
- type
owner
- id
- name
这里每个pets
都可以拥有一个owner
。 要从pet
访问owner
,请调用.parent()
。ps:owner
将id定义为owner_id
作为外键与pets
关联起来,那么owner
就是pets
的parent
。一个pets
有且只有一个owner
。(也就是一个儿子有且只有有一个爹)
let pet: Pet = ...
let owner = try pet.parent(pet.ownerId, Owner.self).get()
parent()
的参数是外键和parent
的类型。
Convenience
为了使查询parent
更简单,我们给model添加一个方法:
extension Pet {
func owner() throws -> Parent<Owner> {
return try parent(ownerId)
}
}
在扩展了Pet
类之后,我们不需要再在ownerId
前加pet.
了。另外,由于返回类型已经确定,所以也不需要Owner.self
这个参数了。
Parent<T>
类型是一个可查询的对象,也就意味着同样可以使用delete
和filter
对parent
进行操作。
try pet.owner().delete()
获取parent
则需要调用get()
:
let owner = try pet.owner().get()
Children
Children
和Parent
关系相反,总结之前的例子,也可以通过owner
查询pets
。
let owner: Owner = ...
let pets = owner.children(Pet.self).all()
参数只有child
的类型。
Convenience
和Parent
一样,扩展添加一个查询child
的方法:
extension Owner {
func pets() throws -> Children<Pet> {
return try children()
}
}
返回值中明确了返回类型,所以也不再需要Pet.self
这个参数了。
Children<T>
也是可查询对象,所以可以调用first()
,all()
,filter()
等方法。
let coolPets = try owner.pets().filter("type", .in, ["Dog", "Ferret"]).all()
Siblings(兄弟姐妹😁)
Siblings
不同于Parent
和Child
关系,需要Pivot
类作为枢纽。
举个例子,假设我们要让我们的pets
有多个toys
。 但是我们也希望toys
能被多种pets
共享。 我们需要一个Pivot
实体(也就是单独创建一个关联表)。
pets
- id
- type
- owner_id
toys
- id
- name
pets_toys
- id
- pet_id
- toy_id
如你所见,创建了一个实体:pets_toys
或者是Pivot<Pet, Toy>
。
Convenience
给Pet
添加一个快捷方法:
extension Pet {
func toys() throws -> Siblings<Toy> {
return try siblings()
}
}
反过来给Toy
也添加一个:
extension Toy {
func pets() throws -> Siblings<Pet> {
return try siblings()
}
}
然后就可以像查询child
关系那样去查询了:
let pet: Pet = ...
let toys = pet.toys().all()
下面是创建“多对多”关系的方法:
var toy: Toy = ... // Create a new toy
try toy.save() // Save the toy to the db
var pet: Pet = ... // Create a new pet
try pet.save() // Save the pet to the db
// Link them together in the db
var pivot = Pivot<Toy, Pet>(toy, pet) // Create the relationship
try pivot.save() // Save the relationship to the db
Preparation
为了备份通过Pivot
建立的关系,只要简单的将这个pivot
添加到Droplet
的preparations
中。
let drop = Droplet()
drop.preparations += [
Toy.self,
Pet.self,
Pivot<Toy, Pet>.self
]
<b>总结:</b>这节主要介绍了表之间的关联关系,以及如何通过关联关系进行数据查询。最后介绍了如何对Pivot
进行备份。