Sequelize 中文文檔 v4 - Associations - 關聯

Associations - 關聯

此係列文章的應用示例已發佈於 GitHub: sequelize-docs-Zh-CN. 能夠 Fork 幫助改進或 Star 關注更新. 歡迎 Star.html

Sequelize Docs 中文文檔目錄git

本部分描述 sequelize 中的各類關聯類型。 當調用 User.hasOne(Project) 這樣的方法時,咱們說 User 模型(該函數被調用的模型)是 sourceProject 模型(模型被傳遞爲參數)是 targetgithub

一對一關聯

一對一關聯是經過單個外鍵鏈接的兩個模型之間的關聯。sql

BelongsTo

BelongsTo 關聯是在 source model 上存在一對一關係的外鍵的關聯。數據庫

一個簡單的例子是 Player 經過 player 的外鍵做爲 Team 的一部分。segmentfault

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 的狀況下,將使用它代替目標模型名稱。ide

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進行設置。 它們適用於不一樣的場景。 讓咱們用一個例子來研究這個差別。

假設咱們有兩個表能夠連接 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 模型中

一對多關聯

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

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}
    }
  }]
});

做用域

本節涉及關聯做用域。 有關關聯做用域與相關模型上的做用域的定義,請參閱 做用域

關聯做用域容許您在關聯上放置一個做用域(一套 getcreate 的默認屬性)。做用域能夠放在相關聯的模型(關聯的target)上,也能夠經過表上的 n:m 關係。

1:m

假設咱們有表評論,帖子和圖像。 一個評論能夠經過 commentable_idcommentable 關聯到一個圖像或一個帖子 - 咱們說 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字符串轉換爲getImagegetPost的一個調用,提供一個註釋是屬於一個帖子仍是一個圖像的抽象概念。您能夠將普通選項對象做爲參數傳遞給 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' }),那麼您將同時擁有 subscriptionIdtheSubscriptionId,由於 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,則會被更新。經過將onUpdateonDelete選項傳遞給關聯調用,能夠覆蓋這些選項。驗證選項爲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 支持, 謝謝.

相關文章
相關標籤/搜索