User.hasOne(Project)
之類的方法時,我們說 User
模型(函數被調用的模型)是 source 。 Project
模型(作為參數傳遞的模型)是 target 。
一、一對一關聯
一對一關聯是通過單個外鍵連接的兩個模型之間的關聯。
1、BelongsTo:源model - 屬於的意思
屬於的意思:源屬於目標,在源上添加目標外鍵
BelongsTo 關聯是在 source model 上存在一對一關系的外鍵的關聯。一個簡單的例子是 Player 通過 player 的外鍵作為 Team 的一部分。
const Player = this.sequelize.define('player', {/* attributes */}); const Team = this.sequelize.define('team', {/* attributes */}); Player.belongsTo(Team); // 將向 Player 添加一個 teamId 屬性以保存 Team 的主鍵值
2、外鍵
默認情況下,將從目標模型名稱和目標主鍵名稱生成 belongsTo 關系的外鍵。
默認的樣式是 camelCase
,但是如果源模型配置為 underscored: true
,那么將使用字段 snake_case
創建 foreignKey。
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
3、目標鍵
目標鍵是源模型上的外鍵列指向的目標模型上的列。 默認情況下,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
4、HasOne:目標model
有一個的意思,源有一個目標,在目標上添加源的外鍵
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。
在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 模型中
hasOne
。 在這種情況下, Coach
適用於 hasOne
,因為 Team
模型將其 Coach
的信息存儲為 coachId
字段。
Coach.hasOne(Team) // `coachId` 將被添加到 Team / Target 模型中
二、一對多關聯 (hasMany)
一對多關聯將一個來源與多個目標連接起來。 而多個目標接到同一個特定的源。
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' }})
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} } }] });
當通過模型不存在主鍵時,Belongs-To-Many會創建唯一鍵。 可以使用 uniqueKey 選項覆蓋此唯一鍵名。
Project.belongsToMany(User, { through: UserProjects, uniqueKey: 'my_custom_unique' })