多对多

在如今的社会,我们非常喜欢给人打上标签,比如 颜值逆天暖烘烘高富帅等等。高富帅并不是某一个人的专利,一个人可以被别人打上多个标签,一个标签也可以打在多个人上面。这就是多对多关系。

声明多对多关系需要用到belongsToMany方法。

  1. User.beblongsToMany(Tag, {through: 'user_tag'});
  2. Tag.belongsToMany(User, {through: 'user_tag'});

在多对多关系的表结构中,无论我们把关系 id 存在双方的任何一个表中,会出现上一节所提到的使用Book.hasOne(User)声明关系,有数据冗余的问题,所以在多对多关系下的表结构需要第三个表来保存它们之间的关系。

而这第三张表,就是上面的 user_tag 。里面有一个 userId 和一个 tagId 字段。

实例

1.新建 tag.ts 文件

  1. import Sequelize from 'sequelize';
  2. import {UserAttributes, UserInstance} from './user';
  3. export interface TagAttributes {
  4. name: string;
  5. }
  6. export interface TagInstance extends Sequelize.Instance<TagAttributes>, TagAttributes {
  7. id: number;
  8. getUsers: Sequelize.BelongsToManyGetAssociationsMixin<UserInstance>,
  9. addUsers: Sequelize.BelongsToManyAddAssociationsMixin<UserInstance, number, any>,
  10. addUser: Sequelize.BelongsToManyAddAssociationMixin<UserInstance, number, any>,
  11. setUser: Sequelize.BelongsToManySetAssociationsMixin<UserInstance, number, any>,
  12. countUsers: Sequelize.BelongsToManyCountAssociationsMixin,
  13. createUser: Sequelize.BelongsToManyCreateAssociationMixin<UserAttributes, UserInstance, any>,
  14. hasUser: Sequelize.BelongsToManyHasAssociationMixin<UserInstance, number>,
  15. hasUsers: Sequelize.BelongsToManyHasAssociationsMixin<UserInstance, number>,
  16. removeUser: Sequelize.BelongsToManyRemoveAssociationMixin<UserInstance, number>,
  17. removeUsers: Sequelize.BelongsToManyRemoveAssociationsMixin<UserInstance, number>,
  18. }
  19. export default function TagDefine(sequelize: Sequelize.Sequelize, dataTypes: Sequelize.DataTypes): Sequelize.Model<TagInstance, TagAttributes> {
  20. const S = dataTypes;
  21. const Tag = sequelize.define<TagInstance, TagAttributes>('Tag', {
  22. name: S.STRING
  23. }, {
  24. timestamps: false
  25. });
  26. (Tag as any).associate = function(this: typeof Tag, models){
  27. this.belongsToMany(models.User, {through: 'user_tag'});
  28. }
  29. return Tag;
  30. }

2.在 user.ts 添加关系代码

  1. getTags: Sequelize.BelongsToManyGetAssociationsMixin<TagInstance>,
  2. addTags: Sequelize.BelongsToManyAddAssociationsMixin<TagInstance, number, any>,
  3. addTag: Sequelize.BelongsToManyAddAssociationMixin<TagInstance, number, any>,
  4. setTag: Sequelize.BelongsToManySetAssociationsMixin<TagInstance, number, any>,
  5. countTags: Sequelize.BelongsToManyCountAssociationsMixin,
  6. createTag: Sequelize.BelongsToManyCreateAssociationMixin<TagAttributes, TagInstance, any>,
  7. hasTag: Sequelize.BelongsToManyHasAssociationMixin<TagInstance, number>,
  8. hasTags: Sequelize.BelongsToManyHasAssociationsMixin<TagInstance, number>,
  9. removeTag: Sequelize.BelongsToManyRemoveAssociationMixin<TagInstance, number>,
  10. removeTags: Sequelize.BelongsToManyRemoveAssociationsMixin<TagInstance, number>,
  1. (User as any).associate = function(this: typeof User,models){
  2. // this.hasOne(models.Book);
  3. this.hasMany(models.Book);
  4. this.belongsToMany(models.Tag, { through: 'user_tag'});
  5. }

3.在 index.ts 里面添加验证代码

  1. import TagDefined, {TagAttributes, TagInstance} from './tag';
  2. const Tag = sequelize.import<TagInstance, TagAttributes>('./tag');
  3. let user = await User.create({email:'belovedyogurt@gmail.com',name: 'yugo'})
  4. await user.createTag({name: '萌新'}); // 为 yugo 添加一个标签
  5. let tag = (await Tag.findAll())[0]; // 拿到 tag 表中第一条数据
  6. const tagUser = (await tag.getUsers())[0]; // 拿到该标签关联的用户的第一个
  7. console.log(user.id == tagUser.id); // 俩边查出来的 user 是否相等

运行之后可以得到一个 true ,说明逻辑正确。而且在数据库中也创建了user_tag关联表,完成以上代码运行之后便可看到数据库中已存数据。