当前位置: 首页 > 文档资料 > Sequelize ORM 实践 >

3.4 多对多

优质
小牛编辑
123浏览
2023-12-01

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

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

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

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

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

实例

1.新建 tag.ts 文件

import Sequelize from 'sequelize';
import {UserAttributes, UserInstance} from './user';

export interface TagAttributes {
  name: string;
}

export interface TagInstance extends Sequelize.Instance<TagAttributes>, TagAttributes {
  id: number;

  getUsers: Sequelize.BelongsToManyGetAssociationsMixin<UserInstance>,
  addUsers: Sequelize.BelongsToManyAddAssociationsMixin<UserInstance, number, any>,
  addUser: Sequelize.BelongsToManyAddAssociationMixin<UserInstance, number, any>,
  setUser: Sequelize.BelongsToManySetAssociationsMixin<UserInstance, number, any>,
  countUsers: Sequelize.BelongsToManyCountAssociationsMixin,
  createUser: Sequelize.BelongsToManyCreateAssociationMixin<UserAttributes, UserInstance, any>,
  hasUser: Sequelize.BelongsToManyHasAssociationMixin<UserInstance, number>,
  hasUsers: Sequelize.BelongsToManyHasAssociationsMixin<UserInstance, number>,
  removeUser: Sequelize.BelongsToManyRemoveAssociationMixin<UserInstance, number>,
  removeUsers: Sequelize.BelongsToManyRemoveAssociationsMixin<UserInstance, number>,

}

export default function TagDefine(sequelize: Sequelize.Sequelize, dataTypes: Sequelize.DataTypes): Sequelize.Model<TagInstance, TagAttributes>  {
    const S = dataTypes;
    const Tag = sequelize.define<TagInstance, TagAttributes>('Tag', {
        name: S.STRING
    }, {
        timestamps: false
    });

    (Tag as any).associate = function(this: typeof Tag, models){
        this.belongsToMany(models.User, {through: 'user_tag'});
    }

    return Tag;
}

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

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

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

import TagDefined, {TagAttributes, TagInstance} from './tag';

const Tag = sequelize.import<TagInstance, TagAttributes>('./tag');

let user = await User.create({email:'belovedyogurt@gmail.com',name: 'yugo'})
await user.createTag({name: '萌新'}); // 为 yugo 添加一个标签

let tag = (await Tag.findAll())[0]; // 拿到 tag 表中第一条数据

const tagUser = (await tag.getUsers())[0]; // 拿到该标签关联的用户的第一个

console.log(user.id == tagUser.id); // 俩边查出来的 user 是否相等

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