如何扩展 Sequelize 模型?

Posted

技术标签:

【中文标题】如何扩展 Sequelize 模型?【英文标题】:How to extend a Sequelize model? 【发布时间】: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 【参考方案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)。但是,我现在正在为此寻找解决方案。下面的例子解决了两个需求:

    我们在同一个表中有两个实体(继承和添加新属性)并且; 有一种方法可以让所有模型都有共同的属性:
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 )

【讨论】:

以上是关于如何扩展 Sequelize 模型?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Sequelize.js 进入包含模型

更改数据库模型 - Sequelize

如何扩展 Sequelize 模型?

如何使用 sequelize 基于 sqlite3 中的“日期”列进行查询?

如何在使用 Sequelize 更改列或添加新列时更新迁移文件

如何将查询逻辑添加到基于 graphql-sequelize 的设置?