runoops.com

Sequelize 模型

模型定义

在 Sequelize 中可以用两种等效的方式定义模型:

  • 调用 sequelize.define(modelName, attributes, options)
  • 扩展 Model 并调用 init(attributes, options)

定义模型后,可通过其模型名称在 sequelize.models 中使用该模型。

使用 sequelize.define:

const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('runoops_test', 'root', '123456', {
    host: 'localhost',
    dialect: 'mysql' /* 选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 其一 */
  });

const User = sequelize.define('User', {
  // 在这里定义模型属性
  firstName: {
    type: DataTypes.STRING,
    allowNull: false
  },
  lastName: {
    type: DataTypes.STRING
    // allowNull 默认为 true
  }
}, {
  // 这是其他模型参数
});

// `sequelize.define` 会返回模型
console.log(User === sequelize.models.User); // true

扩展 Model

const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = new Sequelize('runoops_test', 'root', '123456', {
    host: 'localhost',
    dialect: 'mysql' /* 选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 其一 */
  });

class User extends Model {}

User.init({
  // 在这里定义模型属性
  firstName: {
    type: DataTypes.STRING,
    allowNull: false
  },
  lastName: {
    type: DataTypes.STRING
    // allowNull 默认为 true
  }
}, {
  // 这是其他模型参数
  sequelize, // 我们需要传递连接实例
  modelName: 'User' // 我们需要选择模型名称
});

// 定义的模型是类本身
console.log(User === sequelize.models.User); // true

在内部,sequelize.define 调用 Model.init,因此两种方法本质上是等效的。

公共类字段的注意事项

添加与模型属性之一同名的公共类字段会出现问题. Sequelize 为通过 Model.init 定义的每个属性添加一个 getter 和一个 setter. 添加公共类字段将隐藏那些 getter 和 setter,从而阻止对模型的实际数据的访问。

// 无效的
class User extends Model {
  id; // 此字段将影响 sequelize 的 getter 和 setter. 它应该被删除.
  otherPublicField; // 这个字段不会影响任何东西. 没问题.
}

User.init({
  id: {
    type: DataTypes.INTEGER,
    autoIncrement: true,
    primaryKey: true
  }
}, { sequelize });

const user = new User({ id: 1 });
user.id; // undefined
// 有效的
class User extends Model {
  otherPublicField;
}

User.init({
  id: {
    type: DataTypes.INTEGER,
    autoIncrement: true,
    primaryKey: true
  }
}, { sequelize });

const user = new User({ id: 1 });
user.id; // 1

在 TypeScript 中, 您可以使用 declare 关键字添加键入信息, 而无需添加实际的公共类字段:

// 有效
class User extends Model {
  declare id: number; // 您可以使用 `declare` 关键字添加键入信息, 而无需添加实际的公共类字段.
}

User.init({
  id: {
    type: DataTypes.INTEGER,
    autoIncrement: true,
    primaryKey: true
  }
}, { sequelize });

const user = new User({ id: 1 });
user.id; // 1

表名推断

默认情况下,当未提供表名时,Sequelize 会自动将模型名复数并将其用作表名. 这种复数是通过称为 inflection 的库在后台完成的,因此可以正确计算不规则的复数(例如 person -> people)。

强制表名称等于模型名称

sequelize.define('User', {
  // ... (属性)
}, {
  freezeTableName: true
});

上面的示例将创建一个名为 User 的模型,该模型指向一个也名为 User 的表.

也可以为 sequelize 实例全局定义此行为:

const sequelize = new Sequelize('runoops_test', 'root', '123456', {
    host: 'localhost',
    dialect: 'mysql' /* 选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 其一 */
    freezeTableName: true
  });

这样,所有表将使用与模型名称相同的名称。

直接提供表名

你也可以直接告诉 Sequelize 表名称:

sequelize.define('User', {
// ... (属性)
}, {
tableName: 'Employees'
});

模型同步

可以通过调用一个异步函数(返回一个Promise)model.sync(options)来实现模型同步(执行SQL)。

User.sync() - 如果表不存在,则创建该表(如果已经存在,则不执行任何操作)
User.sync({ force: true }) - 将创建表,如果表已经存在,则将其首先删除
User.sync({ alter: true }) - 这将检查数据库中表的当前状态(它具有哪些列,它们的数据类型等),然后在表中进行必要的更改以使其与模型匹配.

实例

await User.sync({ force: true });
console.log("用户模型表刚刚(重新)创建!");

一次同步所有模型

你可以使用 sequelize.sync() 自动同步所有模型. 示例:

await sequelize.sync({ force: true });
console.log("所有模型均已成功同步.");

同步的数据表users 结构如下:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `firstName` varchar(255) NOT NULL,
  `lastName` varchar(255) DEFAULT NULL,
  `createdAt` datetime NOT NULL,
  `updatedAt` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

删除表

删除与模型相关的表:

await User.drop();
console.log("用户表已删除!");

删除所有表:

await sequelize.drop();
console.log("所有表已删除!");

数据库安全检查

如上所示,syncdrop操作是破坏性的. Sequelize 使用 match 参数作为附加的安全检查,该检查将接受 RegExp:

// 仅当数据库名称以 '_test' 结尾时,它才会运行.sync()
sequelize.sync({ force: true, match: /_test$/ });

时间戳

默认情况下,Sequelize 使用数据类型 DataTypes.DATE 自动向每个模型添加 createdAt 和 updatedAt 字段。

对于带有 timestamps: false 参数的模型,可以禁用此行为:

sequelize.define('User', {
  // ... (属性)
}, {
  timestamps: false
});

也可以只启用 createdAt/updatedAt 之一,并为这些列提供自定义名称:

class Foo extends Model {}
Foo.init({ /* 属性 */ }, {
  sequelize,

  // 不要忘记启用时间戳!
  timestamps: true,

  // 不想要 createdAt
  createdAt: false,

  // 想要 updatedAt 但是希望名称叫做 updateTimestamp
  updatedAt: 'updateTimestamp'
});

列声明简写语法

如果关于列的唯一指定内容是其数据类型,则可以缩短语法:

// 例如:
sequelize.define('User', {
  name: {
    type: DataTypes.STRING
  }
});

// 可以简写为:
sequelize.define('User', { name: DataTypes.STRING });

默认值

默认情况下,Sequelize 假定列的默认值为 NULL. 可以通过将特定的 defaultValue 传递给列定义来更改此行为:

sequelize.define('User', {
  name: {
    type: DataTypes.STRING,
    defaultValue: "John Doe"
  }
});

一些特殊的值,例如 DataTypes.NOW,也能被接受:

sequelize.define('Foo', {
  bar: {
    type: DataTypes.DATETIME,
    defaultValue: DataTypes.NOW
    // 这样,当前日期/时间将用于填充此列(在插入时)
  }
});

Captcha Code

0 笔记

分享笔记

Inline Feedbacks
View all notes