Eggjs学习系列(五) Sequelize的使用

本文是Eggjs学习系列的第五部分,主要介绍了如何在Eggjs项目中集成和使用Sequelize ORM框架。内容涵盖Sequelize的安装配置、Sequelize-cli的使用,包括数据库结构的迁移和种子文件,以及如何在项目中创建和使用Model。此外,还提到了如何处理typescript与sequelize的集成问题。

Eggjs学习系列(五) Sequelize的使用

简单的数据库操作通过使用egg-mysql 插件基本上可以满足需求,而在一些较为复杂的应用中,我们可能会需要一个 ORM 框架来帮助我们管理数据层的代码。sequelize 是一个广泛使用的 ORM 框架,支持多种数据库。ORM 即使用面向对象的方式,通过操作对象来实现与数据库之前的交流,完成CRUD的动作。

安装和配置插件

由于我们使用的是 TypeScript 语言,这里采用的是 egg-sequelize-ts 插件,插件使用 sequelize-typescript 来操作数据库。

npm install --save egg-sequelize-ts mysql2

config/plugin.ts 中引入 egg-sequelize 插件

const plugin: EggPlugin = {
  // static: true,
  sequelize: {
    enable: true,
    package: 'egg-sequelize-ts',
  },
};

config/config.default.ts 中编写 sequelize 配置

import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg';
export default (appInfo: EggAppInfo) => {
  const config = {} as PowerPartial<EggAppConfig>;
  // add your special config in here
  const bizConfig = {
    sequelize: {
      dialect: 'mysql',
      host: '127.0.0.1',
      port: 3306,
      password: 'xxx',
      database: 'egg',
    },
  }
  // the return config will combines to EggAppConfig
  return {
    ...config,
    ...bizConfig,
  };
};

Sequelize-cli 使用

在日常开发种,经常会遇到数据库结构发生变更的情况,这时候需要使用 Migrations 来管理数据结构的变更,以实现在不同的开发环境和迭代切换中,快速变更数据结构。

安装 sequelize-cli

npm install --save sequelize-cli

在Nodejs Web应用中建立初始的数据访问层

npx sequelize init

将创建以下文件夹:

  • config 包含配置文件,它告诉CLI如何连接数据库
  • models 包含您的项目的所有模型
  • migrations 包含所有迁移文件
  • seeders 包含所有种子文件

注意: 可以通过 .sequelizerc 设置 生成文件夹的位置。

// .sequelizerc
'use strict';

const path = require('path');

module.exports = {
  config: path.join(__dirname, 'database/config.json'), 
  'migrations-path': path.join(__dirname, 'database/migrations'),
  'seeders-path': path.join(__dirname, 'database/seeders'),
  'models-path': path.join(__dirname, 'app/model'),
};

sequelize-cli 常用命令

npx sequelize db:create  # 创建数据库
npx sequelize db:drop # 删除数据库

# 通过命令行创建模型,使用 model:generate 命令
# name: 模型名称
# attributes: 模型的属性列表
# 创建模型 User, 模型包括属性 firstName、lastName、email
npx sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string
# 创建模型 Role, 模型包括属性 roleName
npx sequelize model:generate --name Role --attributes roleName:string

# 数据库迁移
npx sequelize db:migrate
# 撤销上一次迁移操作
# 可使用 --name xxx 指定具体迁移
npx sequelize db:migrate:undo
# 撤销所有迁移操作
npx sequelize db:migrate:undo:all

# 创建种子,用于生成测试数据
npx sequelize seed:generate --name demo-role
npx sequelize seed:generate --name demo-user
# 插入演示数据到数据库种
npx sequelize db:seed:all
# 撤销指定种子文件
npx sequelize db:seed:undo --seed 指定种子文件
# 撤销所有种子文件
db:seed:undo:all

sequelize-cli 实践

在eggjs项目中创建 database 目录存放数据库信息。根据上面的 .sequelizrc 文件,执行指令

npx sequelize init:config
npx sequelize init:migrations

会生成 database/config.json 文件和 database/migrations 目录,修改 database/config.json 中的服务器配置。修改好配置,生成一个 migration 文件。

npx sequelize migration:generate --name=init-users

通过生成的 migration文件来初始化表。sequelize-cli 默认生成的 js 文件,修改文件后缀为 ts 编写内容

// ${timestamp}-init-users.ts 文件
import { QueryInterface } from 'sequelize';
export default {
  up: async (queryInterface: QueryInterface, Sequelize) => {
    const { INTEGER, STRING, DATE } = Sequelize;
    await queryInterface.createTable('users', {
      id: { type: INTEGER, primaryKey: true, autoIncrement: true },
      name: STRING(30),
      age: INTEGER,
      created_at: DATE,
      updated_at: DATE,
    });
  },

  down: async (queryInterface: QueryInterface) => {
    await queryInterface.dropTable('users');
  },
};

sequelize-cli 执行 migrate 进行数据库变更

# 升级数据库
npx sequelize db:migrate
# 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
# npx sequelize db:migrate:undo
# 可以通过 `db:migrate:undo:all` 回退到初始状态
# npx sequelize db:migrate:undo:all

正常的 js 文件在执行完上面的步骤后,便完成了迁移,但由于我们采用了 typescript 语法,需要先进行处理:

  1. package.json 中添加执行命令

    "scripts": {
    	"sequelize-cli-ts": "node -r ts-node/register ./node_modules/sequelize-cli/lib/sequelize"   
    }
    
  2. 执行命令

    yarn sequelize-cli-ts db:migrate # yarn 执行
    npm run sequelize-cli-ts db:migrate # npm 执行
    

sequelize 实践

app/model/ 目录下编写 user 这个 Model

import { AutoIncrement, Column, DataType, Model, PrimaryKey, Table } from 'sequelize-typescript';
@Table({
  modelName: 'user',
  timestamps: false,
})
export class User extends Model<User> {

  @PrimaryKey
  @AutoIncrement
  @Column({
    type: DataType.INTEGER(11),
    comment: '用户ID',
  })
  id: number;

  @Column({
    type: DataType.STRING(30),
    comment: '用户姓名',
  })
  name: string;

  @Column({
    comment: '用户年龄',
  })
  age: number;
}
export default () => User;

这个 Model 就可以在 Controller 和 Service 中通过 app.model.User 或者 ctx.model.User 访问到了,例如我们编写 app/controller/users.ts

import { Controller } from 'egg';
function toInt(str) {
  if (typeof str === 'number') return str;
  if (!str) return str;
  return parseInt(str, 10) || 0;
}

export default class UsersController extends Controller {
  // 查询用户
  public async index() {
    const ctx = this.ctx;
    const query = { limit: toInt(ctx.query.limit), offset: toInt(ctx.query.offset) };
    ctx.body = await ctx.model.User.findAll(query);
  }

  // 展示用户详情
  async show() {
    const ctx = this.ctx;
    ctx.body = await ctx.model.User.findByPk(toInt(ctx.params.id));
  }

  // 创建用户
  async create() {
    const ctx = this.ctx;
    const { name, age } = ctx.request.body;
    const user = await ctx.model.User.create({ name, age });
    ctx.status = 201;
    ctx.body = user;
  }

  // 更新用户
  async update() {
    const ctx = this.ctx;
    const id = toInt(ctx.params.id);
    const user = await ctx.model.User.findByPk(id);
    if (!user) {
      ctx.status = 404;
      return;
    }

    const { name, age } = ctx.request.body;
    await user.update({ name, age });
    ctx.body = user;
  }

  // 删除用户
  async destroy() {
    const ctx = this.ctx;
    const id = toInt(ctx.params.id);
    const user = await ctx.model.User.findByPk(id);
    if (!user) {
      ctx.status = 404;
      return;
    }

    await user.destroy();
    ctx.status = 200;
  }
}

最后添加路由

import { Application } from 'egg';
export default (app: Application) => {
  const { controller, router } = app;
  // ...
  router.resources('users', '/users', controller.users);
};

注意:

sequelize 默认添加数据的时候会增加一些常用字段如creatAt等等。如果不需要这些属性,可以在 @table 注解里设置取消

@Table({
    tableName: "project",
    timestamps: false,
    freezeTableName: true
})

参考资料

sequelize-cli 使用
sequelize-typescript

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值