Sequelize:多对多表(CROSS TABLE)关联到另一个表

Posted

技术标签:

【中文标题】Sequelize:多对多表(CROSS TABLE)关联到另一个表【英文标题】:Sequelise : Many To Many table(CROSS TABLE) associated to other table 【发布时间】:2021-04-15 18:26:52 【问题描述】:

这是我的图表数据库:https://i.stack.imgur.com/CGAwh.png

我用 SEQUELIZE 制作了我的数据库模型:

型号:级别

module.exports = (sequelize, DataTypes) => 
  const Level = sequelize.define(
    'Level',
    
      level_id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      label: 
        type: DataTypes.STRING,
        allowNull: false,
        unique: 
          args: true,
          msg: 'Level:Label already exist!',
        ,
        validate: 
          notEmpty:  msg: `Level:Label cannot be empty!` ,
          notNull:  msg: `Level:Label cannot be NULL!` ,
        ,
      ,
      ref: 
        type: DataTypes.STRING,
        allowNull: true,
      ,
      description: 
        type: DataTypes.TEXT,
        allowNull: true,
      ,
    ,
    
      tableName: 'levels',
      timestamps: false,
    
  );

  Level.associate = (models) => 
    Level.belongsToMany(models.Test, 
      through: models.testHasLevel,
      foreignKey: 'level_id',
      otherKey: 'test_id',
      timestamps: false,
    );
  ;

  return Level;
;

型号:测试:

    module.exports = (sequelize, DataTypes) => 
  const Test = sequelize.define(
    'Test',
    
      test_id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      label: 
        type: DataTypes.STRING,
        allowNull: false,
        validate: 
          notEmpty:  msg: `Test:label cannot be empty!` ,
          notNull:  msg: `Test:label cannot be NULL!` ,
        ,
      ,
      isInternal: 
        type: DataTypes.BOOLEAN,
        defaultValue: false,
        allowNull: false,
        validate: 
          notEmpty:  msg: `Test:isInternal cannot be empty!` ,
          notNull:  msg: `Test:isInternal cannot be NULL!` ,
        ,
      ,
      parent_id: 
        type: DataTypes.INTEGER,
        defaultValue: null,
        allowNull: true,
      ,
    ,
    
      tableName: 'tests',
      timestamps: false,
    
  );

  Test.associate = (models) => 
    Test.belongsToMany(models.Level, 
      through: models.testHasLevel,
      foreignKey: 'test_id',
      otherKey: 'level_id',
      timestamps: false,
    );
    Test.hasMany(models.Test,  foreignKey: 'parent_id', as: 'children' );
  ;

  return Test;
;

模型:测试有模型

    module.exports = (sequelize, DataTypes) => 
  const testHasLevel = sequelize.define(
    'testHasLevel',
    ,
    
      id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      tableName: 'test_has_level',
      timestamps: false,
    
  );
  testHasLevel.associate = (models) => 
    testHasLevel.belongsTo(models.Test, 
      foreignKey: 'test_id',
      targetKey: 'test_id',
    );
    testHasLevel.belongsTo(models.Level, 
      foreignKey: 'level_id',
      targetKey: 'level_id',
    );
  ;

  return testHasLevel;
;

我也做了会话模型:

module.exports = (sequelize, DataTypes) => 
  const Session = sequelize.define(
    'Session',
    
      session_id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      institut_id: 
        type: DataTypes.INTEGER,
      ,
      start: 
        type: DataTypes.DATE,
      ,
      end: 
        type: DataTypes.DATE,
      ,
      test_id: 
        type: DataTypes.INTEGER,
      ,
      level_id: 
        type: DataTypes.INTEGER,
      ,
      limitDateSubscribe: 
        type: DataTypes.DATE,
      ,
      placeAvailable: 
        type: DataTypes.INTEGER,
      ,
    ,
    
      tableName: 'sessions',
      timestamps: false,
    
  );
  Session.associate = (models) => 
    Session.hasMany(models.sessionHasUser,  foreignKey: 'session_id' );
  ;
  return Session;
;

但我不知道如何“绑定”SESSIONTEST_HAS_LEVEL 和 Sequelize .... 我应该改变什么?因为我知道最后一个版本的续集不允许使用“复合密钥”。

换句话说: 如何正确地将交叉表与另一表的一对多关系关联起来?

【问题讨论】:

【参考方案1】:

型号:级别

module.exports = (sequelize, DataTypes) => 
  const Level = sequelize.define(
    "Level",
    
      level_id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      label: 
        type: DataTypes.STRING,
        allowNull: false,
        unique: 
          args: true,
          msg: "Level:Label already exist!",
        ,
        validate: 
          notEmpty:  msg: `Level:Label cannot be empty!` ,
          notNull:  msg: `Level:Label cannot be NULL!` ,
        ,
      ,
      ref: 
        type: DataTypes.STRING,
        allowNull: true,
      ,
      description: 
        type: DataTypes.TEXT,
        allowNull: true,
      ,
    ,
    
      tableName: "levels",
      timestamps: false,
    
  );

  Level.associate = (models) => 
    Level.hasMany(models.testHasLevel, 
      foreignKey: "level_level_id",
      as: "levels",
    );
  ;

  return Level;
;

模型:测试

module.exports = (sequelize, DataTypes) => 
  const Test = sequelize.define(
    "Test",
    
      test_id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      label: 
        type: DataTypes.STRING,
        allowNull: false,
        validate: 
          notEmpty:  msg: `Test:label cannot be empty!` ,
          notNull:  msg: `Test:label cannot be NULL!` ,
        ,
      ,
      isInternal: 
        type: DataTypes.BOOLEAN,
        defaultValue: false,
        allowNull: false,
        validate: 
          notEmpty:  msg: `Test:isInternal cannot be empty!` ,
          notNull:  msg: `Test:isInternal cannot be NULL!` ,
        ,
      ,
      parent_id: 
        type: DataTypes.INTEGER,
        defaultValue: null,
        allowNull: true,
      ,
    ,
    
      tableName: "tests",
      timestamps: false,
    
  );

  Test.associate = (models) => 
    Test.hasMany(models.testHasLevel, 
      foreignKey: "test_test_id",
      as: "tests",
    );
    Test.hasMany(models.Test,  foreignKey: "parent_id", as: "children" );
  ;

  return Test;
;

模型:测试有水平

module.exports = (sequelize, DataTypes) => 
  const testHasLevel = sequelize.define(
    "testHasLevel",
    
      id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      test_test_id: 
        type: DataTypes.INTEGER,
      ,
      level_level_id: 
        type: DataTypes.INTEGER,
      ,
    ,
    
      tableName: "test_has_level",
      timestamps: false,
    
  );
  testHasLevel.associate = (models) => 
    testHasLevel.belongsTo(models.Test, 
      foreignKey: "test_test_id",
      as: "tests",
    );
    testHasLevel.belongsTo(models.Level, 
      foreignKey: "level_level_id",
      as: "levels",
    );
    testHasLevel.hasMany(models.Session, 
      foreignKey: "test_has_level_id",
      as: "test_has_level",
    );
  ;

  return testHasLevel;
;

模型:会话

module.exports = (sequelize, DataTypes) => 
  const Session = sequelize.define(
    "Session",
    
      session_id: 
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      ,
      institut_id: 
        type: DataTypes.INTEGER,
      ,
      start: 
        type: DataTypes.DATE,
      ,
      end: 
        type: DataTypes.DATE,
      ,
      test_has_level_id: 
        type: DataTypes.INTEGER,
      ,
      limitDateSubscribe: 
        type: DataTypes.DATE,
      ,
      placeAvailable: 
        type: DataTypes.INTEGER,
      ,
    ,
    
      tableName: "sessions",
      timestamps: false,
    
  );
  Session.associate = (models) => 
    Session.belongsTo(models.testHasLevel, 
      foreignKey: "test_has_level_id",
      as: "test_has_level",
    );
  ;
  return Session;
;

【讨论】:

以上是关于Sequelize:多对多表(CROSS TABLE)关联到另一个表的主要内容,如果未能解决你的问题,请参考以下文章

如何查询多对多关系sequelize?

在 Sequelize.js 中为多对多关系添加默认角色

如何在 Sequelize 中按多对多关系排序?

Sequelize 查询在多对多关系中显示附加数据

Sequelize 多对多关系同一张表

Sequelize多态多对多 - `add` mixin不起作用