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 支持, 谢谢.

相关文章
相关标签/搜索