Sequelize數據庫關聯


  本博客描述 Sequelize 中的各種關聯類型。當調用諸如 User.hasOne(Project) 之類的方法時,我們說 User 模型(函數被調用的模型)是 sourceProject 模型(作為參數傳遞的模型)是 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。

5、HasOne 和 BelongsTo 之間的區別

  在Sequelize 1:1關系中可以使用HasOne和BelongsTo進行設置。 它們適用於不同的場景。 讓我們用一個例子來研究這個差異。假設我們有兩個表可以鏈接 PlayerTeam 。 讓我們定義他們的模型。

const Player = this.sequelize.define('player', {/* attributes */}) const Team  = this.sequelize.define('team', {/* attributes */});

  當我們連接 Sequelize 中的兩個模型時,我們可以將它們稱為一對 sourcetarget 模型。像這樣

  將 Player 作為 sourceTeam 作為 target

Player.belongsTo(Team); //
Player.hasOne(Team);

  將 Team 作為 sourcePlayer 作為 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 模型中

二、一對多關聯 (hasMany)

  一對多關聯將一個來源與多個目標連接起來。 而多個目標接到同一個特定的源。

const User = sequelize.define('user', {/* ... */}) const Project = sequelize.define('project', {/* ... */}) // 好。 現在,事情變得更加復雜(對用戶來說並不真實可見)。 // 首先我們來定義一個 hasMany 關聯
Project.hasMany(User, {as: 'Workers'})

  這會將 projectIdproject_id 屬性添加到 User。Project 的實例將獲得訪問器 getWorkerssetWorkers

  有時您可能需要在不同的列上關聯記錄,您可以使用 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 的新模型,具有等效的外鍵projectIduserId。 屬性是否為camelcase取決於由表(在這種情況下為UserProject)連接的兩個模型。

  定義 throughrequired。 Sequelize 以前會嘗試自動生成名稱,但並不總是導致最合乎邏輯的設置。

  這將添加方法 getUsers, setUsers, addUser,addUsersProject, 還有 getProjects, setProjects, addProject, 和 addProjectsUser

  有時,您可能需要在關聯中使用它們時重命名模型。 讓我們通過使用別名(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} } }] });

  當通過模型不存在主鍵時,Belongs-To-Many會創建唯一鍵。 可以使用 uniqueKey 選項覆蓋此唯一鍵名。

Project.belongsToMany(User, { through: UserProjects, uniqueKey: 'my_custom_unique' })

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM