模型是數(shù)據(jù)庫中Swift數(shù)據(jù)的展示。因此,它們對于大多數(shù)Fluent的api來說都是至關(guān)重要的。
本指南概述了與模型相關(guān)的協(xié)議需求和方法。
再瞧瞧
請參閱入門指南,了解如何使用模型。
增刪改查(CRUD)
模型有幾種基本的創(chuàng)建、讀取、更新和刪除的方法。
保存(Save)
將實體持久化到數(shù)據(jù)存儲中并設(shè)置id
屬性。
let pet = Pet(name: "Spud", age: 2)
try pet.save()
查找(Find)
找到提供的標識符或返回nil
的模型。
guard let pet = try Pets.find(42) else {
throw Abort.notFound
}
print(pet.name)
刪除(Delete)
如果實體以前被獲取或保存,則從數(shù)據(jù)存儲中刪除該實體。
try pet.delete()
全部(All)
為該模型返回所有實體。
for pet in try Pets.all() {
print(pet.name)
}
計數(shù)(Count)
返回該模型的所有實體的計數(shù)。
let count = try Pets.count()
數(shù)據(jù)塊(Chunk)
返回為該模型的所有實體提供一個提供的大小的數(shù)組。
這是一種解析大型數(shù)據(jù)集的所有模型的好方法。
try Pets.chunk(20) { pets in
//
}
查詢(Query)
為這個Model
創(chuàng)建一個Query
實例。
let query = try Pet.makeQuery()
要了解關(guān)于復雜查詢的更多信息,請參見查詢(query)部分。
時間戳(Timestamps)
要向您的模型添加時間戳,只需繼承Timestampable
。
extension User: Timestampable { }
您可以在任何模型實例上訪問更新(updated at)和創(chuàng)建(created at)。
user.updatedAt // Date?
user.createdAt // Date?
當對時間戳數(shù)據(jù)進行過濾或排序時,您可以使用來自類的時間戳鍵。
let newUsers = try User
.makeQuery()
.filter(User.createdAtKey, .greaterThan, ...)
.all()
如果有定制的需要,還可以覆蓋時間戳鍵。
extension User: Timestampable {
static var updatedAtKey: String { return "custom_updated_at" }
static var createdAtKey: String { return "custom_created_at" }
}
遷移(Migration)
Timestampable
的模型將自動創(chuàng)建并更新在數(shù)據(jù)庫創(chuàng)建(database create)調(diào)用期間添加的鍵。
如果您需要手動將Timestampable
添加到現(xiàn)有的模型中,那么您可以在遷移中使用date()
方法。
database.modify(User.self) { builder in
builder.date(User.createdAtKey)
builder.date(User.updatedAtKey)
}
軟刪除(Soft Delete)
“軟刪除”是一種“刪除”模型,從所有獲取和更新查詢到流暢,但實際上并不是從數(shù)據(jù)庫中刪除模型。軟刪除的模型也可以恢復。
要使您的模型具有可軟的可刪除性,只需將其繼承SoftDeletable
。
extension User: SoftDeletable { }
一旦您的模型是軟的,所有調(diào)用delete()
的調(diào)用將在標記中設(shè)置刪除,而不是實際刪除模型。
要恢復模型,請調(diào)用.restore()
。要從數(shù)據(jù)庫中刪除一個模型,請調(diào)用.forceDelete()
。
如果您有定制的需要,也可以覆蓋軟刪除鍵。
extension User: SoftDeletable {
static var deletedAtKey: String { return "custom_deleted_at" }
}
包含刪除(Including Deleted)
當一個模型被軟刪除時,它不會被任何用流利的查詢構(gòu)建器所做的查詢所影響。
要包含軟刪除的模型,例如,如果您想要恢復它們,請使用query builder中的.withSoftDeleted()
方法。
let allUsers = try User.makeQuery().withSoftDeleted().all()
生命周期(Lifecycle)
您可以連接到模型的軟刪除事件。
extension User: SoftDeletable {
func willSoftDelete() throws { ... }
func didSoftDelete() { ... }
func willForceDelete() throws { ... }
func didForceDelete() { ... }
func willRestore() throws { ... }
func didRestore() { ... }
}
筆記
在一個will
鉤子上投擲,將阻止動作的發(fā)生。
遷移(Migration)
SoftDeletable
模型將自動在數(shù)據(jù)庫創(chuàng)建(database create )調(diào)用期間添加一個刪除鍵。
如果您需要手動添加一個現(xiàn)有模型的SoftDeletable
,您可以在遷移中使用date()
方法。
database.modify(User.self) { builder in
builder.date(User.deletedAtKey, optional: true)
}
便利(Convenience)
斷言存在(Assert Exists)
模型的標識符屬性是可選的,因為模型可能還沒有被保存。
如果模型還沒有通過調(diào)用assertExists()
來保存,那么您可以獲得標識符或者拋出錯誤。
let id = try pet.assertExists()
print(id) // not optional
生命周期(Life Cycle)
可以在您的模型上實現(xiàn)以下生命周期方法,以便將其連接到內(nèi)部操作。
/// Called before the entity will be created.在創(chuàng)建實體之前調(diào)用。
/// Throwing will cancel the creation.投擲將會取消創(chuàng)建。
func willCreate() throws
/// Called after the entity has been created.在創(chuàng)建實體之后調(diào)用。
func didCreate()
/// Called before the entity will be updated.在實體將被更新之前調(diào)用。
/// Throwing will cancel the update.投擲將會取消更新。
func willUpdate() throws
/// Called after the entity has been updated.在實體更新后調(diào)用。
func didUpdate()
/// Called before the entity will be deleted.在實體被刪除之前調(diào)用。
/// Throwing will cancel the deletion.投擲將取消刪除。
func willDelete() throws
/// Called after the entity has been deleted.該實體已被刪除。
func didDelete()
筆記
拋出一個willFoo()
方法將取消操作。
下面是實現(xiàn)didDelete
方法的一個示例。
final class Pet: Model {
...
func didDelete() {
print("Deleted \(name)")
}
}
實體(Entity)
實體是模型遵循的基本的流暢協(xié)議。在保存、獲取或刪除模型時,它負責提供數(shù)據(jù)庫或查詢可能需要的所有信息。
名字(Name)
這個模型的唯一關(guān)系名稱。也用于內(nèi)部存儲。例如:Pet=“pet”。
這種價值通常不應該過分夸大。
final class Pet: Model {
static let name = "pet"
}
實體(Entity)
這個模型的復數(shù)關(guān)系名稱。用作集合或表名。
例如:Pet=“pets”。
如果您的模型的表名是非標準的,那么這個值應該被覆蓋。
final class Pet: Model {
static let entity = "pets"
}
ID類型(ID Type)
用于本地和外id鍵的標識符類型。
例如:uuid,integer,等等。
如果數(shù)據(jù)庫中的某個特定模型使用了不同的ID類型,那么該值應該被過度使用。
final class Pet: Model {
static let idType: IdentifierType = .uuid
}
還可以使用配置在數(shù)據(jù)庫級別上覆蓋這一層。
Config/fluent.json
{
"idType": "uuid"
}
或用編程。
drop.database?.idType = .uuid
關(guān)鍵的命名約定(Key Naming Convention)
用于外id鍵、表名等的命名傳輸。
例如:snake_case與camelCase。
如果數(shù)據(jù)庫中的某個特定模型使用不同的鍵命名約定,那么該值應該被覆蓋。
final class Pet: Model {
static let keyNamingConvention = .snake_case
}
還可以使用配置在數(shù)據(jù)庫級別上覆蓋這一層。
Config/fluent.json
{
"keyNamingConvention": "snake_case"
}
或用編程。
drop.database?.keyNamingConvention = .snake_case
ID Key
與該實體的標識鍵對應的列的名稱。
默認的是“database.driver.idKey”,然后是“id”
final class Pet: Model {
static let idKey = "id"
}
外來的ID KEY(Foreign ID Key)
當從其他表或集合引用時,指向該實體的id的列的名稱。
例如:“foo_id”。
final class Pet: Model {
static let foreignIdKey = "pet_id"
}