Model
Model是任何應(yīng)用程序模型的基本協(xié)議,特別是要持久化的模型。
Model僅適用于Vapor,在Fluent里等價于Entity
Example
我們來創(chuàng)建一個簡單的用戶模型
final class User {
var name: String
init(name: String) {
self.name = name
}
}
符合模型的第一步要導(dǎo)入Vapor和Fluent。
import Vapor
import Fluent
然后添加一致性到你的類。
final class User: Model {
...
}
接著編譯器通知你需要實現(xiàn)一些方法。
ID
第一個必需屬性是一個標(biāo)識符。當(dāng)從數(shù)據(jù)庫中獲取模型時,此屬性將包含標(biāo)識符。如果為nil,則保存模型時將被設(shè)置。
final class User: Model {
var id: Node?
...
}
Node Initializable
下一個要求是從持久化數(shù)據(jù)創(chuàng)建模型的方法。模型使用NodeInitializable來實現(xiàn)這一點。
final class User: Model {
init(node: Node, in context: Context) throws {
id = try node.extract("id")
name = try node.extract("name")
}
...
}
id和name是我們預(yù)期數(shù)據(jù)庫中的列或字段而被命名的。提取調(diào)用方法被標(biāo)記為嘗試,因為如果值不存在或者錯誤類型,它將拋出錯誤。
Node Representable
現(xiàn)在我們已經(jīng)涵蓋了初始化模型。我們需要顯示如何將其保存回數(shù)據(jù)庫。模型使用NodeRepresentable來實現(xiàn)這一點。
final class User: Model {
func makeNode(context: Context) throws -> Node {
return try Node(node: [
"id": id,
"name": name
])
}
...
}
保存用戶時,將調(diào)用makeNode()方法,并將生成的節(jié)點保存到數(shù)據(jù)庫。id和name是我們預(yù)期數(shù)據(jù)庫中的列或字段而被命名的。
在大多數(shù)情況下,不需要關(guān)心
makeNode(context :)方法的上下文參數(shù)。它是協(xié)議的一部分,允許在更高級或特定場景中進行擴展。
Preparations
一些數(shù)據(jù)庫(如MySQL)需要為新模式做好準備。在MySQL中,這意味著創(chuàng)建一個新的表。準備工作也等同于遷移,因為它們可以用于在已創(chuàng)建模式之后更改模式。
Prepare
假設(shè)我們正在使用SQL數(shù)據(jù)庫。要為我們的User類準備數(shù)據(jù)庫,我們需要創(chuàng)建一個表。如果使用的數(shù)據(jù)庫如Mongo,可以不用實現(xiàn)這個方法。
final class User {
static func prepare(_ database: Database) throws {
try database.create("users") { users in
users.id()
users.string("name")
}
}
...
}
創(chuàng)建一個名為users的表,該表具有一個標(biāo)識符字段和一個具有鍵名稱name的字符串字段。這與init(node:Node)和makeNode() - > Node方法相匹配。
Revert
可以創(chuàng)建可選的準備還原。如果vapor run prepare --revert被調(diào)用,則這個將被執(zhí)行。
final class User {
static func revert(_ database: Database) throws {
try database.delete("users")
}
...
}
上面是刪除users表。
Preparations as Migrations
如果要在創(chuàng)建初始模式后將表單添加到表中,可以創(chuàng)建符合Preparation的結(jié)構(gòu)或類,如下所示:
struct AddFooToBar: Preparation {
static func prepare(_ database: Database) throws {
try database.modify("bars", closure: { bar in
bar.string("foo", length: 150, optional: false, unique: false, default: nil)
})
}
static func revert(_ database: Database) throws {
}
}
然后,在Droplet設(shè)置中,添加以下行:drop.preparations.append(AddFooToBar.self)
Droplet
要在應(yīng)用程序引導(dǎo)時運行這些準備工作,必須將Model添加到Droplet。
let drop = Droplet()
drop.preparations.append(User.self)
注意:在
Droplet運行前必須附上準備工作。
Full Model
這就是最終的users模型:
import Vapor
import Fluent
final class User: Model {
var id: Node?
var name: String
init(name: String) {
self.name = name
}
init(node: Node, in context: Context) throws {
id = try node.extract("id")
name = try node.extract("name")
}
func makeNode(context: Context) throws -> Node {
return try Node(node: [
"id": id,
"name": name
])
}
static func prepare(_ database: Database) throws {
try database.create("users") { users in
users.id()
users.string("name")
}
}
static func revert(_ database: Database) throws {
try database.delete("users")
}
}
Interacting
現(xiàn)在users符合Model,它有很多新的方法,如find(),query(),makeJSON()等等。
Fetch
Models can be fetched by their database identifier
中文(簡體)
模型可以通過其數(shù)據(jù)庫標(biāo)識符獲取
let user = try User.find(42)
Save
新創(chuàng)建的模型可以保存到數(shù)據(jù)庫。
var user = User(name: "Vapor")
try user.save()
print(user.id) // prints the new id
Delete
具有標(biāo)識符的持久模型可以被刪除。
try user.delete()
Model vs. Entity
模型有幾個額外的一致性而Fluent的Entity就沒有。
public protocol Model: Entity, JSONRepresentable, StringInitializable, ResponseRepresentable {}
從協(xié)議中可以看出,Vapor的Model自動轉(zhuǎn)換為JSON,Response,甚至可以用于類型安全路由。
Options
更改表/集合名稱.
static var entity = "new_name"
繼續(xù)學(xué)習(xí)vapor學(xué)習(xí)教程-目錄