【问题标题】:How to extend a Sequelize model?如何扩展 Sequelize 模型?
【发布时间】:2018-05-11 17:03:27
【问题描述】:

有没有一种方法可以让我使用一个基类,该基类具有我的模型的所有公共属性和方法,但不与数据库表链接,然后我可以在定义新模型时扩展这个基类。

在这里,我在 node express 中创建了基本的 person 模型。我需要从基类扩展 person 类。

const person = sequelizeClient.define('person', {
    name: {
      type: DataTypes.STRING,
      allowNull: false
    }
  }, {
    hooks: {
      beforeCount(options) {
        options.raw = true;
      }
    }
  });

  const base = sequelizeClient.define('base', {
    id: {
      type: Sequelize.INTEGER,
      autoIncrement: true,
      primaryKey: true
    },
    createdBy: {
      type: Sequelize.INTEGER,
    },
    updatedBy: {
      type: Sequelize.INTEGER,
    },
    deletedBy: {
      type: Sequelize.INTEGER,
    }
  }, {
    hooks: {
      beforeCount(options) {
        options.raw = true;
      }
    }
  });

在文档中说

Sequelize 模型是 ES6 类。您可以非常轻松地添加自定义实例或类级别的方法。

如何使用 ES6 扩展类模式来做到这一点?

有一个类似的问题,但最近没有更新。 How to extend Sequelize model

【问题讨论】:

  • 你使用的是什么版本的 Sequelize?
  • 续集版本为v4.23.1

标签: javascript express ecmascript-6 sequelize.js feathersjs


【解决方案1】:

如何使用 ES6 扩展类模式来做到这一点?

Sequelize 文档中的声明让开发人员有点困惑。这并不意味着您可以使用 ES6 类语法扩展定义的模型,如下所示。

const User = db.define('User', {
  name: sequelize.STRING,
  age: sequelize.INTEGER
});

// This is impossible.
class Staff extends User {
  ...
}

但您可以通过访问原型来定义实例方法,如下所示。

const User = db.define('User', {
  name: sequelize.STRING,
  age: sequelize.INTEGER
});

User.Instance.prototype.test = function() {
  return `Name: ${this.name}, Age: ${this.age}`
}

User.create({ name: "John", age: 10 });
User.findOne().then((user) => {
  console.log(user.test()) // "Name: John, Age: 10"
});

您在 Sequelize 文档中提到的声明实际上是说您可以使用 prototype based 扩展来增强模型行为,因此您不能执行您在问题中尝试执行的模型继承之类的事情。

关于ES6类语法在Sequelize中的实现提案有很多讨论,比如this,但看起来还在讨论中。

【讨论】:

  • 你能举个例子,基本属性是通过基于原型的扩展继承的吗?
  • 我在回答中给了你一个例子。 User.Instance.prototype.test = function { ... } 的行就是那个。
  • 如果不是太麻烦,请您在这里解释一下“实例”一词的用法。而且我想做的是定义一个带有属性和钩子的javascript对象,并使用该对象来定义所有其他模型,同时添加或覆盖方法和属性。
  • 我很确定这是可能的,但我没有机会进一步调查。答案包含适用于 Sequelize v3 的旧 PR 的链接,而当前版本是 v4。
  • @estus 我尝试了类似class Staff extends User { ... } 的方法,但出现错误。我们可以看到任何文档或问题吗?
【解决方案2】:

Sequelize 似乎无法扩展类模型,那么扩展 sequelize 对象的 config 对象怎么样?它的工作量稍大一些,但提供了最接近的体验并保持相对清洁。当然,同时使用 attributesoptions 参数需要使用 2 个单独的类或对组合类进行适当的解构。

class Base {
    constructor() {
        this.id = {
            type: Sequelize.INTEGER,
            autoIncrement: true,
            primaryKey: true
        };
        ...
    }
}

class Person extends Base {
    constructor() {
        super();
        this.name = {
            type: DataTypes.STRING,
            allowNull: false
        };
        ...
    }
}

// using separate class for attributes
const person = sequelize.define('person', new Person());

// possible destructuring of attributes/options
const someModel= sequelize.define('someModel', (new SomeModel()).attributes, (new SomeModel()).options);

【讨论】:

    【解决方案3】:

    我认为尚不支持此功能 (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 )
    

    【讨论】:

      猜你喜欢
      • 2013-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-16
      • 2011-01-11
      • 2014-12-19
      • 2017-02-26
      • 2021-01-16
      相关资源
      最近更新 更多