Associations – 關聯
此係列文章的應用示例已釋出於 GitHub: sequelize-docs-Zh-CN. 可以 Fork 幫助改進或 Star 關注更新. 歡迎 Star.
本部分描述 sequelize 中的各種關聯型別。 當呼叫 User.hasOne(Project)
這樣的方法時,我們說 User
模型(該函式被呼叫的模型)是 source 而 Project
模型(模型被傳遞為引數)是 target 。
一對一關聯
一對一關聯是通過單個外來鍵連線的兩個模型之間的關聯。
BelongsTo
BelongsTo 關聯是在 source model 上存在一對一關係的外來鍵的關聯。
一個簡單的例子是 Player 通過 player 的外來鍵作為 Team 的一部分。
const Player = this.sequelize.define(`player`, {/* attributes */});
const Team = this.sequelize.define(`team`, {/* attributes */});
Player.belongsTo(Team); // 將向 Team 新增一個 teamId 屬性以儲存 Team 的主鍵值
外來鍵
預設情況下,將從目標模型名稱和目標主鍵名稱生成 belongsTo 關係的外來鍵。
預設的樣式是 camelCase
,但是如果源模型配置為 underscored: true
,那麼 foreignKey 將是snake_case
。
const User = this.sequelize.define(`user`, {/* attributes */})
const Company = this.sequelize.define(`company`, {/* attributes */});
User.belongsTo(Company); // 將 companyId 新增到 user
const User = this.sequelize.define(`user`, {/* attributes */}, {underscored: true})
const Company = this.sequelize.define(`company`, {
uuid: {
type: Sequelize.UUID,
primaryKey: true
}
});
User.belongsTo(Company); // 將 company_uuid 新增到 user
在已定義 as
的情況下,將使用它代替目標模型名稱。
const User = this.sequelize.define(`user`, {/* attributes */})
const UserRole = this.sequelize.define(`userRole`, {/* attributes */});
User.belongsTo(UserRole, {as: `role`}); // 將 role 新增到 user 而不是 userRole
在所有情況下,預設外來鍵可以用 foreignKey
選項覆蓋。
當使用外來鍵選項時,Sequelize 將按原樣使用:
const User = this.sequelize.define(`user`, {/* attributes */})
const Company = this.sequelize.define(`company`, {/* attributes */});
User.belongsTo(Company, {foreignKey: `fk_company`}); // 將 fk_company 新增到 User
目標鍵
目標鍵是源模型上的外來鍵列指向的目標模型上的列。 預設情況下,belongsTo 關係的目標鍵將是目標模型的主鍵。 要定義自定義列,請使用 targetKey
選項。
const User = this.sequelize.define(`user`, {/* attributes */})
const Company = this.sequelize.define(`company`, {/* attributes */});
User.belongsTo(Company, {foreignKey: `fk_companyname`, targetKey: `name`}); // 新增 fk_companyname 到 User
HasOne
HasOne 關聯是在 target model 上存在一對一關係的外來鍵的關聯。
const User = sequelize.define(`user`, {/* ... */})
const Project = sequelize.define(`project`, {/* ... */})
// 單向關聯
Project.hasOne(User)
/*
在此示例中,hasOne 將向 User 模型新增一個 projectId 屬性 !
此外,Project.prototype 將根據傳遞給定義的第一個引數獲取 getUser 和 setUser 的方法。
如果啟用了 underscore 樣式,則新增的屬性將是 project_id 而不是 projectId。
外來鍵將放在 users 表上。
你也可以定義外來鍵,例如 如果您已經有一個現有的資料庫並且想要處理它:
*/
Project.hasOne(User, { foreignKey: `initiator_id` })
/*
因為Sequelize將使用模型的名稱(define的第一個引數)作為訪問器方法,
還可以將特殊選項傳遞給hasOne:
*/
Project.hasOne(User, { as: `Initiator` })
// 現在你可以獲得 Project#getInitiator 和 Project#setInitiator
// 或者讓我們來定義一些自己的參考
const Person = sequelize.define(`person`, { /* ... */})
Person.hasOne(Person, {as: `Father`})
// 這會將屬性 FatherId 新增到 Person
// also possible:
Person.hasOne(Person, {as: `Father`, foreignKey: `DadId`})
// 這將把屬性 DadId 新增到 Person
// 在這兩種情況下,你都可以:
Person#setFather
Person#getFather
// 如果你需要聯結表兩次,你可以聯結同一張表
Team.hasOne(Game, {as: `HomeTeam`, foreignKey : `homeTeamId`});
Team.hasOne(Game, {as: `AwayTeam`, foreignKey : `awayTeamId`});
Game.belongsTo(Team);
即使它被稱為 HasOne 關聯,對於大多數1:1關係,您通常需要BelongsTo關聯,因為 BelongsTo 將會在 hasOne 將新增到目標的源上新增 foreignKey。
HasOne 和 BelongsTo 之間的區別
在Sequelize 1:1關係中可以使用HasOne和BelongsTo進行設定。 它們適用於不同的場景。 讓我們用一個例子來研究這個差異。
假設我們有兩個表可以連結 Player 和 Team 。 讓我們定義他們的模型。
const Player = this.sequelize.define(`player`, {/* attributes */})
const Team = this.sequelize.define(`team`, {/* attributes */});
當我們連線 Sequelize 中的兩個模型時,我們可以將它們稱為一對 source 和 target 模型。像這樣
將 Player 作為 source 而 Team 作為 target
Player.belongsTo(Team);
//或
Player.hasOne(Team);
將 Team 作為 source 而 Player 作為 target
Team.belongsTo(Player);
//Or
Team.hasOne(Player);
HasOne 和 BelongsTo 將關聯鍵插入到不同的模型中。 HasOne 在 target 模型中插入關聯鍵,而 BelongsTo 將關聯鍵插入到 source 模型中。
下是一個示例,說明了 BelongsTo 和 HasOne 的用法。
const Player = this.sequelize.define(`player`, {/* attributes */})
const Coach = this.sequelize.define(`coach`, {/* attributes */})
const Team = this.sequelize.define(`team`, {/* attributes */});
假設我們的 Player
模型有關於其團隊的資訊為 teamId
列。 關於每個團隊的 Coach
的資訊作為 coachId
列儲存在 Team
模型中。 這兩種情況都需要不同種類的1:1關係,因為外來鍵關係每次出現在不同的模型上。
當關於關聯的資訊存在於 source 模型中時,我們可以使用 belongsTo
。 在這種情況下,Player
適用於 belongsTo
,因為它具有 teamId
列。
Player.belongsTo(Team) // `teamId` 將被新增到 Player / Source 模型中
當關於關聯的資訊存在於 target 模型中時,我們可以使用 hasOne
。 在這種情況下, Coach
適用於 hasOne
,因為 Team
模型將其 Coach
的資訊儲存為 coachId
欄位。
Coach.hasOne(Team) // `coachId` 將被新增到 Team / Target 模型中
一對多關聯
一對多關聯將一個來源與多個目標連線起來。 而多個目標接到同一個特定的源。
const User = sequelize.define(`user`, {/* ... */})
const Project = sequelize.define(`project`, {/* ... */})
// 好。 現在,事情變得更加複雜(對使用者來說並不真實可見)。
// 首先我們來定義一個 hasMany 關聯
Project.hasMany(User, {as: `Workers`})
這將新增屬性 projectId
或 project_id
到 User。 Project 的例項將獲得訪問器 getWorkers
和 setWorkers
。 我們讓它保持原樣,讓它成為單向關聯。
但是我們想要更多! 讓我們在下一節中以其他方式定義並建立一個多對多的關聯:
有時您可能需要在不同的列上關聯記錄,您可以使用 sourceKey
選項:
const City = sequelize.define(`city`, { countryCode: Sequelize.STRING });
const Country = sequelize.define(`country`, { isoCode: Sequelize.STRING });
// 在這裡,我們可以根據國家程式碼連線國家和城市
Country.hasMany(City, {foreignKey: `countryCode`, sourceKey: `isoCode`});
City.belongsTo(Country, {foreignKey: `countryCode`, targetKey: `isoCode`});
多對多關聯
多對多關聯用於將源與多個目標相連線。 此外,目標也可以連線到多個源。
Project.belongsToMany(User, {through: `UserProject`});
User.belongsToMany(Project, {through: `UserProject`});
這將建立一個名為 UserProject 的新模型,具有等效的外來鍵projectId
和userId
。 屬性是否為camelcase
取決於由表(在這種情況下為User
和Project
)連線的兩個模型。
定義 through
為 required。 Sequelize 以前會嘗試自動生成名稱,但並不總是導致最合乎邏輯的設定。
這將新增方法 getUsers
, setUsers
, addUser
,addUsers
到 Project
, 還有 getProjects
, setProjects
, addProject
, 和 addProjects
到 User
.
有時,您可能需要在關聯中使用它們時重新命名模型。 讓我們通過使用別名(as
)選項將 users 定義為 workers 而 projects 定義為t asks。 我們還將手動定義要使用的外來鍵:
User.belongsToMany(Project, { as: `Tasks`, through: `worker_tasks`, foreignKey: `userId` })
Project.belongsToMany(User, { as: `Workers`, through: `worker_tasks`, foreignKey: `projectId` })
foreignKey
將允許你在 through 關係中設定 source model 鍵。
otherKey
將允許你在 through 關係中設定 target model 鍵。
User.belongsToMany(Project, { as: `Tasks`, through: `worker_tasks`, foreignKey: `userId`, otherKey: `projectId`})
當然你也可以使用 belongsToMany 定義自我引用:
Person.belongsToMany(Person, { as: `Children`, through: `PersonChildren` })
// 這將建立儲存物件的 ID 的表 PersonChildren。
如果您想要連線表中的其他屬性,則可以在定義關聯之前為連線表定義一個模型,然後再說明它應該使用該模型進行連線,而不是建立一個新的關聯:
const User = sequelize.define(`user`, {})
const Project = sequelize.define(`project`, {})
const UserProjects = sequelize.define(`userProjects`, {
status: DataTypes.STRING
})
User.belongsToMany(Project, { through: UserProjects })
Project.belongsToMany(User, { through: UserProjects })
要向 user 新增一個新 project 並設定其狀態,您可以將額外的 options.through
傳遞給 setter,其中包含連線表的屬性
user.addProject(project, { through: { status: `started` }})
預設情況下,上面的程式碼會將 projectId 和 userId 新增到 UserProjects 表中, 刪除任何先前定義的主鍵屬性 – 表將由兩個表的鍵的組合唯一標識,並且沒有其他主鍵列。 要在 UserProjects
模型上強新增一個主鍵,您可以手動新增它。
const UserProjects = sequelize.define(`userProjects`, {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
status: DataTypes.STRING
})
使用多對多你可以基於 through 關係查詢並選擇特定屬性。 例如通過 through 使用findAll
User.findAll({
include: [{
model: Project,
through: {
attributes: [`createdAt`, `startedAt`, `finishedAt`],
where: {completed: true}
}
}]
});
作用域
本節涉及關聯作用域。 有關關聯作用域與相關模型上的作用域的定義,請參閱 作用域。
關聯作用域允許您在關聯上放置一個作用域(一套 get
和 create
的預設屬性)。作用域可以放在相關聯的模型(關聯的target)上,也可以通過表上的 n:m 關係。
1:m
假設我們有表評論,帖子和影像。 一個評論可以通過 commentable_id
和 commentable
關聯到一個影像或一個帖子 – 我們說 Post 和 Image 是 Commentable
const Comment = this.sequelize.define(`comment`, {
title: Sequelize.STRING,
commentable: Sequelize.STRING,
commentable_id: Sequelize.INTEGER
});
Comment.prototype.getItem = function(options) {
return this[`get` + this.get(`commentable`).substr(0, 1).toUpperCase() + this.get(`commentable`).substr(1)](options);
};
Post.hasMany(this.Comment, {
foreignKey: `commentable_id`,
constraints: false,
scope: {
commentable: `post`
}
});
Comment.belongsTo(this.Post, {
foreignKey: `commentable_id`,
constraints: false,
as: `post`
});
Image.hasMany(this.Comment, {
foreignKey: `commentable_id`,
constraints: false,
scope: {
commentable: `image`
}
});
Comment.belongsTo(this.Image, {
foreignKey: `commentable_id`,
constraints: false,
as: `image`
});
constraints: false,
禁用引用約束 – 由於 commentable_id
列引用了幾個表,我們不能新增一個 REFERENCES
約束。 請注意,Image – > Comment 和 Post – > Comment 關係分別定義了一個作用域:commentable: `image`
和 commentable: `post`
。 使用關聯功能時自動應用此作用域:
image.getComments()
SELECT * FROM comments WHERE commentable_id = 42 AND commentable = `image`;
image.createComment({
title: `Awesome!`
})
INSERT INTO comments (title, commentable_id, commentable) VALUES (`Awesome!`, 42, `image`);
image.addComment(comment);
UPDATE comments SET commentable_id = 42, commentable = `image`
Comment
上的 getItem
作用函式完成了圖片 – 它只是將commentable
字串轉換為getImage
或getPost
的一個呼叫,提供一個註釋是屬於一個帖子還是一個影像的抽象概念。您可以將普通選項物件作為引數傳遞給 getItem(options)
,以指定任何條件或包含的位置。
n:m
繼續多型模型的思路,考慮一個 tag 表 – 一個 item 可以有多個 tag,一個 tag 可以與多個 item 相關。
為了簡潔起見,該示例僅顯示了 Post 模型,但實際上 Tag 與其他幾個模型相關。
const ItemTag = sequelize.define(`item_tag`, {
id : {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
tag_id: {
type: DataTypes.INTEGER,
unique: `item_tag_taggable`
},
taggable: {
type: DataTypes.STRING,
unique: `item_tag_taggable`
},
taggable_id: {
type: DataTypes.INTEGER,
unique: `item_tag_taggable`,
references: null
}
});
const Tag = sequelize.define(`tag`, {
name: DataTypes.STRING
});
Post.belongsToMany(Tag, {
through: {
model: ItemTag,
unique: false,
scope: {
taggable: `post`
}
},
foreignKey: `taggable_id`,
constraints: false
});
Tag.belongsToMany(Post, {
through: {
model: ItemTag,
unique: false
},
foreignKey: `tag_id`,
constraints: false
});
請注意,作用域列(taggable
)現在在 through 模型(ItemTag
)上。
我們還可以定義一個更具限制性的關聯,例如,通過應用through 模型(ItemTag
)和目標模型(Tag
)的作用域來獲取所有掛起的 tag。
Post.hasMany(Tag, {
through: {
model: ItemTag,
unique: false,
scope: {
taggable: `post`
}
},
scope: {
status: `pending`
},
as: `pendingTags`,
foreignKey: `taggable_id`,
constraints: false
});
Post.getPendingTags();
SELECT `tag`.* INNER JOIN `item_tags` AS `item_tag`
ON `tag`.`id` = `item_tag`.`tagId`
AND `item_tag`.`taggable_id` = 42
AND `item_tag`.`taggable` = `post`
WHERE (`tag`.`status` = `pending`);
constraints: false
禁用 taggable_id
列上的引用約束。 因為列是多型的,我們不能說它是 REFERENCES
一個特定的表。
命名策略
預設情況下,Sequelize將使用模型名稱(傳遞給sequelize.define
的名稱),以便在關聯時使用模型名稱。 例如,一個名為user
的模型會將關聯模型的例項中的get / set / add User
函式和加入一個名為.user
的屬性,而一個名為User
的模型會新增相同的功能,和一個名為.User
的屬性(注意大寫U)。
正如我們已經看到的,你可以使用as
來關聯模型。 在單個關聯(has one 和 belongs to),別名應該是單數,而對於許多關聯(has many)它應該是複數。 Sequelize然後使用[inflection] [0]庫將別名轉換為其單數形式。 但是,這可能並不總是適用於不規則或非英語單詞。 在這種情況下,您可以提供複數和單數形式的別名:
User.belongsToMany(Project, { as: { singular: `task`, plural: `tasks` }})
// Notice that inflection has no problem singularizing tasks, this is just for illustrative purposes.
如果你知道模型將始終在關聯中使用相同的別名,則可以在建立模型時提供它
const Project = sequelize.define(`project`, attributes, {
name: {
singular: `task`,
plural: `tasks`,
}
})
User.belongsToMany(Project);
這將為使用者例項新增 add/set/get Tasks
方法。
記住,使用as
來更改關聯的名稱也會改變外來鍵的名稱。 當使用as
時,也可以指定外來鍵是最安全的。
Invoice.belongsTo(Subscription)
Subscription.hasMany(Invoice)
不使用 as
,這會按預期新增 subscriptionId
。 但是,如果您要傳送Invoice.belongsTo(Subscription, { as: `TheSubscription` })
,那麼您將同時擁有 subscriptionId
和 theSubscriptionId
,因為 sequelize 不夠聰明,無法確定呼叫是相同關係的兩面。 foreignKey
修正了這個問題;
Invoice.belongsTo(Subscription, , { as: `TheSubscription`, foreignKey: `subscription_id` })
Subscription.hasMany(Invoice, { foreignKey: `subscription_id` )
關聯物件
因為 Sequelize 做了很多神奇的事,所以你必須在設定關聯後呼叫 Sequelize.sync
。 這樣做將允許您進行以下操作:
Project.belongsToMany(Task)
Task.belongsToMany(Project)
Project.create()...
Task.create()...
Task.create()...
// 儲存它們.. 然後:
project.setTasks([task1, task2]).then(() => {
// 已儲存!
})
// 好的,現在它們已經儲存了...我怎麼才能得到他們?
project.getTasks().then(associatedTasks => {
// associatedTasks 是一個 tasks 的陣列
})
// 您還可以將過濾器傳遞給getter方法。
// 它們與你能傳遞給常規查詢器方法的選項相同。
project.getTasks({ where: `id > 10` }).then(tasks => {
// id大於10的任務
})
// 你也可以僅檢索關聯物件的某些欄位。
project.getTasks({attributes: [`title`]}).then(tasks => {
// 使用屬性“title”和“id”檢索任務
})
要刪除建立的關聯,您可以呼叫set方法而不使用特定的ID:
// 刪除與 task1 的關聯
project.setTasks([task2]).then(associatedTasks => {
// 你將只得到 task2
})
// 刪除全部
project.setTasks([]).then(associatedTasks => {
// 你將得到空陣列
})
// 或更直接地刪除
project.removeTask(task1).then(() => {
// 什麼都沒有
})
// 然後再次新增它們
project.addTask(task1).then(function() {
// 它們又回來了
})
反之亦然你當然也可以這樣做:
// project與task1和task2相關聯
task2.setProject(null).then(function() {
// 什麼都沒有
})
對於 hasOne/belongsTo 與其基本相同:
Task.hasOne(User, {as: "Author"})
Task#setAuthor(anAuthor)
可以通過兩種方式新增與自定義連線表的關係的關聯(繼續前一章中定義的關聯):
// 在建立關聯之前,通過向物件新增具有連線表模型名稱的屬性
project.UserProjects = {
status: `active`
}
u.addProject(project)
// 或者在新增關聯時提供第二個options.through引數,其中包含應該在連線表中的資料
u.addProject(project, { through: { status: `active` }})
// 關聯多個物件時,可以組合上述兩個選項。 在這種情況下第二個引數
// 如果沒有提供使用的資料將被視為預設物件
project1.UserProjects = {
status: `inactive`
}
u.setProjects([project1, project2], { through: { status: `active` }})
// 上述程式碼將對專案1記錄無效,並且在連線表中對專案2進行active
當獲取具有自定義連線表的關聯的資料時,連線表中的資料將作為DAO例項返回:
u.getProjects().then(projects => {
const project = projects[0]
if (project.UserProjects.status === `active`) {
// .. 做點什麼
// 由於這是一個真正的DAO例項,您可以在完成操作之後直接儲存它
return project.UserProjects.save()
}
})
如果您僅需要連線表中的某些屬性,則可以提供具有所需屬性的陣列:
// 這將僅從 Projects 表中選擇 name,僅從 UserProjects 表中選擇status
user.getProjects({ attributes: [`name`], joinTableAttributes: [`status`]})
檢查關聯
您還可以檢查物件是否已經與另一個物件相關聯(僅 n:m)。 這是你怎麼做的
// 檢查物件是否是關聯物件之一:
Project.create({ /* */ }).then(project => {
return User.create({ /* */ }).then(user => {
return project.hasUser(user).then(result => {
// 結果是 false
return project.addUser(user).then(() => {
return project.hasUser(user).then(result => {
// 結果是 true
})
})
})
})
})
// 檢查所有關聯的物件是否如預期的那樣:
// 我們假設我們已經有一個專案和兩個使用者
project.setUsers([user1, user2]).then(() => {
return project.hasUsers([user1]);
}).then(result => {
// 結果是 false
return project.hasUsers([user1, user2]);
}).then(result => {
// 結果是 true
})
外來鍵
當您在sequelize模型中建立關聯時,將自動建立具有約束的外來鍵引用。 設定如下:
const Task = this.sequelize.define(`task`, { title: Sequelize.STRING })
const User = this.sequelize.define(`user`, { username: Sequelize.STRING })
User.hasMany(Task)
Task.belongsTo(User)
將生成以下SQL:
CREATE TABLE IF NOT EXISTS `User` (
`id` INTEGER PRIMARY KEY,
`username` VARCHAR(255)
);
CREATE TABLE IF NOT EXISTS `Task` (
`id` INTEGER PRIMARY KEY,
`title` VARCHAR(255),
`user_id` INTEGER REFERENCES `User` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
);
在task和user的關係之 中在task上注入user_id
外來鍵,並將其標記為User
表的引用。預設情況下,如果引用的使用者被刪除,user_id
將被設定為NULL
,如果更新了使用者標識的id,則會被更新。通過將onUpdate
和onDelete
選項傳遞給關聯呼叫,可以覆蓋這些選項。驗證選項為RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL
。
對於1:1和1:m關聯,預設選項為SET NULL
用於刪除, CASCADE
用於更新。對於n:m,兩者的預設值為CASCADE
。這意味著,如果從n:m關聯的一側刪除或更新行,引用該行的連線表中的所有行也將被刪除或更新。
在表之間新增約束意味著在使用sequelize.sync
時,必須以特定順序在資料庫中建立表。如果Task
引用了User
,則必須先建立User
表,然後才能建立Task
表。這有時可能導致迴圈引用,其中後遺症找不到要同步的順序。想象一下檔案和版本的場景。一個文件可以有多個版本,為方便起見,一個文件可以引用它的當前版本。
const Document = this.sequelize.define(`document`, {
author: Sequelize.STRING
})
const Version = this.sequelize.define(`version`, {
timestamp: Sequelize.DATE
})
Document.hasMany(Version) // 這將 document_id 新增到版本
Document.belongsTo(Version, { as: `Current`, foreignKey: `current_version_id`}) // 這將current_version_id新增到文件
但是,上面的程式碼將導致以下錯誤: Cyclic dependency found. `Document` is dependent of itself. Dependency Chain: Document -> Version => Document
.
為了減輕這一點,我們可以將 constraints: false
傳遞給其中一個關聯:
Document.hasMany(Version)
Document.belongsTo(Version, { as: `Current`, foreignKey: `current_version_id`, constraints: false})
這將允許我們正確地同步表:
CREATE TABLE IF NOT EXISTS `Document` (
`id` INTEGER PRIMARY KEY,
`author` VARCHAR(255),
`current_version_id` INTEGER
);
CREATE TABLE IF NOT EXISTS `Version` (
`id` INTEGER PRIMARY KEY,
`timestamp` DATETIME,
`document_id` INTEGER REFERENCES `Document` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
);
強制執行外來鍵引用而不受約束
有時,您可能需要引用另一個表,而不新增任何約束或關聯。 在這種情況下,您可以手動將引用屬性新增到模式定義,並標記它們之間的關係。
// 在我們呼叫 Trainer.hasMany(series) 之後 Series 有一個 外參考鍵 trainer_id=Trainer.id
const Series = sequelize.define(`series`, {
title: DataTypes.STRING,
sub_title: DataTypes.STRING,
description: DataTypes.TEXT,
// 用 `Trainer` 設定外來鍵關係(hasMany)
trainer_id: {
type: DataTypes.INTEGER,
references: {
model: "trainers",
key: "id"
}
}
})
const Trainer = sequelize.define(`trainer`, {
first_name: DataTypes.STRING,
last_name: DataTypes.STRING
});
// 在我們呼叫 Series.hasOne(Video) 之後 Video 有一個 外參考鍵 series_id=Series.id
const Video = sequelize.define(`video`, {
title: DataTypes.STRING,
sequence: DataTypes.INTEGER,
description: DataTypes.TEXT,
// 用 `Series` 設定關係(hasOne)
series_id: {
type: DataTypes.INTEGER,
references: {
model: Series, // 可以是表示表名稱的字串,也可以是對模型的引用
key: "id"
}
}
});
Series.hasOne(Video);
Trainer.hasMany(Series);
用關聯建立
如果所有元素都是新的,則可以在一個步驟中建立具有巢狀關聯的例項。
建立一個 “BelongsTo”, “Has Many” 或 “HasOne” 關聯的元素
考慮以下模型:
const Product = this.sequelize.define(`product`, {
title: Sequelize.STRING
});
const User = this.sequelize.define(`user`, {
first_name: Sequelize.STRING,
last_name: Sequelize.STRING
});
const Address = this.sequelize.define(`address`, {
type: Sequelize.STRING,
line_1: Sequelize.STRING,
line_2: Sequelize.STRING,
city: Sequelize.STRING,
state: Sequelize.STRING,
zip: Sequelize.STRING,
});
Product.User = Product.belongsTo(User);
User.Addresses = User.hasMany(Address);
// 也能用於 `hasOne`
可以通過以下方式在一個步驟中建立一個新的Product
, User
和一個或多個Address
:
return Product.create({
title: `Chair`,
user: {
first_name: `Mick`,
last_name: `Broadstone`,
addresses: [{
type: `home`,
line_1: `100 Main St.`,
city: `Austin`,
state: `TX`,
zip: `78704`
}]
}
}, {
include: [{
association: Product.User,
include: [ User.Addresses ]
}]
});
這裡,我們的使用者模型稱為user
,帶小寫u – 這意味著物件中的屬性也應該是user
。 如果給sequelize.define
指定的名稱為User
,物件中的鍵也應為User
。 對於addresses
也是同樣的,除了它是一個 hasMany
關聯的複數。
用別名建立一個 “BelongsTo” 關聯的元素
可以將前面的示例擴充套件為支援關聯別名。
const Creator = Product.belongsTo(User, {as: `creator`});
return Product.create({
title: `Chair`,
creator: {
first_name: `Matt`,
last_name: `Hansen`
}
}, {
include: [ Creator ]
});
建立 “HasMany” 或 “BelongsToMany” 關聯的元素
我們來介紹將產品與許多標籤相關聯的功能。 設定模型可能如下所示:
const Tag = this.sequelize.define(`tag`, {
name: Sequelize.STRING
});
Product.hasMany(Tag);
// Also works for `belongsToMany`.
現在,我們可以通過以下方式建立具有多個標籤的產品:
Product.create({
id: 1,
title: `Chair`,
tags: [
{ name: `Alpha`},
{ name: `Beta`}
]
}, {
include: [ Tag ]
})
然後,我們可以修改此示例以支援別名:
const Categories = Product.hasMany(Tag, {as: `categories`});
Product.create({
id: 1,
title: `Chair`,
categories: [
{id: 1, name: `Alpha`},
{id: 2, name: `Beta`}
]
}, {
include: [{
model: Categories,
as: `categories`
}]
})
如果這篇文章對您有幫助, 感謝 下方點贊 或 Star GitHub: sequelize-docs-Zh-CN 支援, 謝謝.