【问题标题】:Achieve Single Table Inheritance with Sequelize使用 Sequelize 实现单表继承
【发布时间】:2018-07-04 11:16:32
【问题描述】:

有没有办法使用sequelize创建单表继承?

我想为 Purchase 和 PartialPurchase 模型创建一个 STI,其中我将有一个类型字段,它是“Purchase”或“PartialPurchase”,以及类 Purchase 和 PartialPurchase,它们都将继承自 Operation 类。

我不认为 sequelize 支持这一点,但是否可以实现?

【问题讨论】:

    标签: node.js sequelize.js sti


    【解决方案1】:

    我认为尚不支持此功能 (09/2021)。但是,我现在正在为此寻找解决方案。下面的例子解决了两个需求:

    1. 我们在同一个表中有两个实体(继承和添加新属性)并且;
    2. 有一种方法可以让所有模型都有共同的属性:
    const ModelDiscriminators = {
      Dish: 1,
      Item: 2,
      ItemWithEmail: 3
    }
    
    //Basic field attributes for all entities
    const BasicModelAttributes = { 
      id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true } 
    };
    
    //Table dish have id, name, veg, discriminator attributes
    const Dish = sequelize.define('dish', Object.assign( {}, BasicModelAttributes, {   
      name: { type: DataTypes.STRING },
      veg: { type: DataTypes.BOOLEAN },
      discriminator: { type: DataTypes.INTEGER, defaultValue: () => ModelDiscriminators.Dish }
    } ) );
    
    //Two entities sharing same table. Table Item has id, name, type, discriminator e email(see model ItemWithEmail) atributes
    //Model Item
    const Item = sequelize.define('item', Object.assign( {}, BasicModelAttributes, {   
      name: { type: DataTypes.STRING },
      type: { type: DataTypes.STRING },
      discriminator: { type: DataTypes.INTEGER, defaultValue: () => ModelDiscriminators.Item }
    } ) );
    
    //Model ItemWithEmail inherits all Item attributes and define a new one: e-mail
    //We use the discriminator attribute to query the right records when we make a query or .findAll(+where)
    const ItemWithEmail = sequelize.define('item', Object.assign({}, Item.rawAttributes, { 
      email: { type: DataTypes.STRING },
      discriminator: { type: DataTypes.INTEGER, defaultValue: () => ModelDiscriminators.ItemWithEmail }
    } ) );
    

    我认为这种方法可能是 Sequelize 支持的默认方式。我们可以有一个继承关系,所以我们可以这样写:

    ItemWithEmail.inherits( Item )
    

    如有任何疑问,我很乐意再次为您提供帮助。 heltongoncalves@gmail.com

    【讨论】:

      【解决方案2】:

      嘿,所以我知道你在合理的时间内没有得到答案,但你可以像你说的那样使用一个类型列,它是你的数据库中的一个枚举,然后使用 sequelize 的范围功能。 Scope 的工作范围从查询到模型定义和关联。效果很好。我为带有请求和响应的消息表实现了类似的功能。

      module.exports = function(sequelize, DataTypes) {
        var Message = sequelize.define('Message', {
          id: {
            allowNull: false,
            autoIncrement: true,
            primaryKey: true,
            type: DataTypes.INTEGER,
          },
          type: {
            type: DataTypes.ENUM('REQUEST', 'RESPONSE', 'FILE'),
            allowNull: false
          },
          text: {
            type: DataTypes.TEXT,
            allowNull: false,
          },
          state: {
            type: DataTypes.JSONB,
            allowNull: true,
          },
          userTeamId: {
            type: DataTypes.INTEGER,
            allowNull: false,
          }
        }, );
        Message.associate = (models) => {
          Message.belongsTo(models.UserTeam, { foreignKey: 'userTeamId', targetKey: 'tag'})
        }
        return Message;
      };
      

      然后这就是我做关联的方式。

      module.exports = function(sequelize, DataTypes) {
        var UserTeam = sequelize.define('UserTeam', {
          tag: { type: DataTypes.UUID, allowNull: false, unique: true},
          active: { type: DataTypes.BOOLEAN, defaultValue: false },
          activationNonce: { type: DataTypes.STRING },
          UserId: { type: DataTypes.INTEGER, },
          TeamId: { type: DataTypes.INTEGER, },
          type: DataTypes.ENUM('OWNER', 'ADMIN', 'MEMBER', 'GUEST'),
        },);
        UserTeam.associate = (models) => {
          UserTeam.hasMany(models.Message, { as: 'responses', foreignKey: 'userTeamId', sourceKey: 'tag', scope: {type: 'RESPONSE'}})
          UserTeam.hasMany(models.Message, { as: 'requests', foreignKey: 'userTeamId', sourceKey: 'tag', scope: {type: 'REQUEST'}})
          UserTeam.hasMany(models.Message, { as: 'files', foreignKey: 'userTeamId', sourceKey: 'tag', scope: {type: 'FILE'}})
          UserTeam.hasOne(models.Team, {foreignKey: 'id', sourceKey: 'TeamId'})
          UserTeam.belongsTo(models.User, {foreignKey: 'UserId', sourceKey: 'id'})
        }
        return UserTeam;
      };
      

      关联的好处在于,您可以使用 UserTeam 实例(例如“userteam.getFiles()”)来获取所有关联文件。

      【讨论】:

      • 甜蜜。谢谢你的好例子。我想知道这是否可以被子类化。这对于消息来说有点做作,但是前。 UserMessage、SystemMessage 等假设它们具有不同的功能域。
      猜你喜欢
      • 2014-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-19
      • 2016-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多