如何向 Sequelize-Auto 生成的模型添加关联

Posted

技术标签:

【中文标题】如何向 Sequelize-Auto 生成的模型添加关联【英文标题】:How to add associations to Models generated from Sequelize-Auto 【发布时间】:2019-08-18 04:47:22 【问题描述】:

对于现有的 mysql 数据库,我使用 Sequelize-auto 包来生成模型。但是模型类没有关联。

我有一个 MySQL 数据库,我将它用于 NodeJS Web 项目。我也使用 Sequelize 作为 ORM。由于数据库已经存在,我想将模型类生成为实体。所以我用了sequelize-auto

https://github.com/sequelize/sequelize-auto 生成模型类。但是,当它们生成时,属性已正确设置,但关联并没有与模型类一起出现。所以我在从数据库中获取数据时遇到了问题。

这是使用 sequlize-auto 生成的两个模型类。数据库中有两个表,分别命名为部门和类别。 department.js 和 category.js 是生成的两个模型类

department.js

module.exports = function(sequelize, DataTypes) 
  return sequelize.define('department', 
        department_id: 
            type: DataTypes.INTEGER(11),
            allowNull: false,
            primaryKey: true,
            autoIncrement: true
        ,
        name: 
            type: DataTypes.STRING(100),
            allowNull: false
        ,
        description: 
            type: DataTypes.STRING(1000),
            allowNull: true
        
    , 
        tableName: 'department',
        timestamps: false,
    );
;

category.js

module.exports = function(sequelize, DataTypes) 
  return sequelize.define('category', 
        category_id: 
            type: DataTypes.INTEGER(11),
            allowNull: false,
            primaryKey: true,
            autoIncrement: true
        ,
        department_id: 
            type: DataTypes.INTEGER(11),
            allowNull: false
        ,
        name: 
            type: DataTypes.STRING(100),
            allowNull: false
        ,
        description: 
            type: DataTypes.STRING(1000),
            allowNull: true
        
    , 
        tableName: 'category',
        timestamps: false,
    );
;

那么还需要做什么才能获得关联并成功获取数据。有人可以在这里帮助我。表结构如下。

【问题讨论】:

sequelize auto 没有生成关联的功能,您必须手动执行。但是他们提供了一种使用生成的模型并将关联添加到它们的方法github.com/sequelize/sequelize-auto/issues/34 【参考方案1】:

1) 在您的模型文件夹中创建一个 index.js 文件并添加以下代码

import Sequelize from 'sequelize';

const fs = require('fs');
const path = require('path');

const basename = path.basename(__filename);

const db = ;

// @ts-ignore
const sequelize = new Sequelize('dbname', 'dbUser', 'password', 
  host: '127.0.0.1',
  port: 'PORT',
  dialect: 'mysql',
  define: 
    freezeTableName: true,
    timestamps: false,
  ,
  pool: 
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000,
  ,
  // <http://docs.sequelizejs.com/manual/tutorial/querying.html#operators>
  operatorsAliases: false,
);

const tableModel = ;

fs.readdirSync(__dirname)
  .filter(file => file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js')
  .forEach(file => 
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
    tableModel[model.name] = model;
  );

Object.getOwnPropertyNames(db).forEach(modelName => 
  const currentModel = db[modelName];
  Object.getOwnPropertyNames(currentModel.rawAttributes).forEach(attributeName => 
    if (
      Object.prototype.hasOwnProperty.call(
        currentModel.rawAttributes[attributeName],
        'references'
      ) &&
      Object.prototype.hasOwnProperty.call(
        currentModel.rawAttributes[attributeName].references,
        'model'
      ) &&
      Object.prototype.hasOwnProperty.call(
        currentModel.rawAttributes[attributeName].references,
        'key'
      )
    ) 
      if (
        !(
          currentModel.rawAttributes[attributeName].references.model &&
          currentModel.rawAttributes[attributeName].references.key
        )
      ) 
        console.log(
          `*SKIPPED* $modelName $attributeName references a model $currentModel.rawAttributes[attributeName].references.model with key $currentModel.rawAttributes[attributeName].references.key`
        );
        return;
      

      console.log(
        `$modelName $attributeName references a model $currentModel.rawAttributes[attributeName].references.model with key $currentModel.rawAttributes[attributeName].references.key`
      );
      const referencedTable =
        tableModel[currentModel.rawAttributes[attributeName].references.model];

      currentModel.belongsTo(referencedTable,  foreignKey: attributeName );
      referencedTable.hasMany(currentModel,  foreignKey: attributeName );

    
  );
);

// @ts-ignore
db.sequelize = sequelize;
// @ts-ignore
db.Sequelize = Sequelize;

// eslint-disable-next-line eol-last
module.exports = db;

2) 在您的解析器内部只需参考上述内容:

const db = require('../assets/models/index');

【讨论】:

【参考方案2】:

添加到他基于here 的@CodingLittles 答案。

我添加了以下内容以进行多对多关联:

enum Junctions 
  user = 'user',
  roles = 'roles',


enum JuntiontThrough 
  userroles = 'userroles',



interface JunctionObject 
  junctionBelongsTo?: any;


const checkIfAttrExists= (obj, value) => 
  return Object.prototype.hasOwnProperty.call(obj, value);
;

const checkRefrence = (obj, attr, value) => 
  return obj.rawAttributes[attr].references[value];
;


export const getJunction = (junc: Junctions): JunctionObject => 
  const junctions = 
    user: 
      junctionBelongsTo: [
         key: Junctions.roles, value: juntiontThrough.userroles 
      ],
    ,
    roles: 
      junctionBelongsTo: [ key: Junctions.user, value: juntiontThrough.userroles ],
    ,
  [junc];

  if (!junctions) return ;

  return junctions;
;


  const models = Object.getOwnPropertyNames(db);

models.forEach(modelName => 
  const currentModel = db[modelName];
  const junction = getJunction(modelName as Junctions);

  if (!_.isEmpty(junction)) 
    // eslint-disable-next-line array-callback-return
    junction.junctionBelongsTo.reduce((key, value) => 
      currentModel.belongsToMany(db[value.key], 
        through: db[value.value],
      );
    , );
  

  const attributes = Object.getOwnPropertyNames(currentModel.rawAttributes);

  attributes.forEach(attributeName => 
    if (
      checkIfAttrExists(currentModel.rawAttributes[attributeName], 'references') &&
      checkIfAttrExists(currentModel.rawAttributes[attributeName].references, 'model') &&
      checkIfAttrExists(currentModel.rawAttributes[attributeName].references, 'key')
    ) 
      if (
        !(
          checkRefrence(currentModel, attributeName, 'model') &&
          checkRefrence(currentModel, attributeName, 'key')
        )
      ) 
        return;
      

      const referencedTable =
        tableModel[currentModel.rawAttributes[attributeName].references.model];

      if (!(modelName.toString() in juntiontThrough)) 
        console.log(
          `$modelName $attributeName references a model $currentModel.rawAttributes[attributeName].references.model with key $currentModel.rawAttributes[attributeName].references.key`
        );
        currentModel.belongsTo(referencedTable,  foreignKey: attributeName );
        referencedTable.hasMany(currentModel,  foreignKey: attributeName );
      
    
  );
)

请注意,要使多对多关系起作用,您必须像我在 getJunction 函数中所做的那样手动添加关系

【讨论】:

【参考方案3】:

我遵循sequelize-auto (init-models.ts) 上的打字稿示例中演示的模式 - 在现有的 initModels 函数中,在 js 中可以正常工作。

export function initModels(sequelize: Sequelize) 
  Product.initModel(sequelize);
  Supplier.initModel(sequelize);
  
  Supplier.hasMany(Product,  as: "products", foreignKey: "supplierId");
  
  return ...

【讨论】:

以上是关于如何向 Sequelize-Auto 生成的模型添加关联的主要内容,如果未能解决你的问题,请参考以下文章

nodejs利用sequelize-auto 根据数据库的table 生成model

如何首先使用代码向 Identity 默认表 AspNetUsers 添加多对多关系?

sequelize 中的引用字段是啥?

node开发

向 Reportlab Canvas 对象添加分页符

如何向现有代码添加分页?