Egg企业级实战(三)- 数据库

1,653 阅读4分钟

本文按照完成的开发流程从实例的角度,一步步地搭建出一个开箱即用的Egg.js 应用,让我们开始吧!

完整项目地址:gitee.com/koukaile/eg…

本系列文章目录

01.使用sequelize管理数据库

在 Node.js 社区中,sequelize 是一个广泛使用的 ORM 框架,它支持 MySQL、PostgreSQL、SQLite 和 MSSQL 等多个数据源。

sequelize的使用

  • 安装
npm install --save egg-sequelize mysql2
  • 在 config/plugin.js 中引入 egg-sequelize 插件
exports.sequelize = {
  enable: true,
  package: 'egg-sequelize',
};
  • 在 config/config.default.js(或者按环境配置中讲的配置) 中编写 sequelize 配置(注意freezeTableName和timestamps)
config.sequelize = {
    //数据库类型
    dialect: 'mysql',
    // host
    host: 'localhost',
    // 端口号
    port: '3306',
    // 用户名
    user: 'admin',
    // 密码
    password: '123456',
    // 数据库名
    database: 'root',
    // 时区,sequelize有很多自动时间的方法,都是和时区相关的,记得设置成东8区(+08:00)
    timezone: '+08:00',
    define: {
      timestamps: false, //timestamps默认值是true,如实是true会自动添加上 create_time 和update_time两个字段
      freezeTableName: true //freezeTableName默认值是 false 如果是false的话,会自动在表名后加s复数
    },
};

sequelize-cli 管理

在项目的演进过程中,每一个迭代都有可能对数据库数据结构做变更,怎样跟踪每一个迭代的数据变更,并在不同的环境(开发、测试、CI)和迭代切换中,快速变更数据结构呢?这时候我们就需要 Migrations 来帮我们管理数据结构的变更了。
sequelize 提供了 sequelize-cli 工具来实现 Migrations,我们也可以在 egg 项目中引入 sequelize-cli。

  • 安装 sequelize-cli
npm install --save-dev sequelize-cli
  • 在 egg 项目中,我们希望将所有数据库 Migrations 相关的内容都放在 database 目录下,所以我们在项目根目录下新建一个 .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'),
};
  • 初始化 Migrations 配置文件和目录
npx sequelize init:config
npx sequelize init:migrations
  • database/config.json 文件和 database/migrations 目录
    我们修改一下 database/config.json 中的内容,将其改成我们项目中使用的数据库配置:
{
  "development": {
    "username": "admin",
    "password": "123456",
    "database": "EggZoneFrame",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": {
    "username": "admin",
    "password": "123456",
    "database": "EggZoneFrame",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "admin",
    "password": "123456",
    "database": "EggZoneFrame",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}
  • 创建表 此时 sequelize-cli 和相关的配置也都初始化好了,我们可以开始编写项目的第一个 Migration 文件来创建我们的一个 user 表了
npx sequelize migration:generate --name=init-user

执行完后会在 database/migrations 目录下生成一个 migration 文件(${timestamp}-init-users.js),我们修改它来处理初始化 users 表:

'use strict';

module.exports = {
  // 在执行数据库升级时调用的函数,创建 users 表
  up: async (queryInterface, Sequelize) => {
    const { INTEGER, DATE, STRING } = Sequelize;
    await queryInterface.createTable('user', {
      id: { type: INTEGER, primaryKey: true, autoIncrement: true },
      name: STRING(30),
      age: INTEGER,
      created_at: DATE,
      updated_at: DATE,
    });
  },
  // 在执行数据库降级时调用的函数,删除 users 表
  down: async queryInterface => {
    await queryInterface.dropTable('user');
  },
};
  • 执行 migrate 进行数据库变更
# 升级数据库
npx sequelize db:migrate

# 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
npx sequelize db:migrate:undo

# 可以通过 `db:migrate:undo:all` 回退到初始状态
npx sequelize db:migrate:undo:all

执行之后,我们的数据库初始化就完成了。

编写代码

现在终于可以开始编写代码实现业务逻辑了,首先我们来在 app/model/ 目录下编写 user 这个 Model:

'use strict';

module.exports = app => {
  const { STRING, INTEGER, DATE } = app.Sequelize;

  const User = app.model.define('user', {
    id: { type: INTEGER, primaryKey: true, autoIncrement: true },
    name: STRING(30),
    age: INTEGER,
    created_at: DATE,
    updated_at: DATE,
  });

  return User;
};

这个 Model 就可以在 Controller 和 Service 中通过 app.model.User 或者 ctx.model.User 访问到了

  • controllerc层编写
'use strict';

/**
 * @Controller
**/

const Controller = require('egg').Controller;

class HomeController extends Controller {
  async User() {
    const { ctx } = this;
    ctx.body = await this.service.home.User();
  }
}

module.exports = HomeController;
  • service层编写
'use strict';

const Service = require('egg').Service;

class HomeService extends Service {
  async User() 
    const { ctx } = this;
    const res = await ctx.model.User.findAll();
    return res
  }
}

module.exports = HomeService;
  • controller 挂载到路由:
// app/router.js
module.exports = app => {
  const { router, controller } = app;
  router.resources('/user/login', controller.user);
};

02.sequelize查询语法

增加

await this.ctx.model.UserAuth.create({
  identityType: IdentityType.username,
  identifier: username,
  credential: password,
});

删除

await this.ctx.model.User.destroy({ where: { id: userId } });

修改

await ctx.model.User.update({ alias: '233' }, { where: { id: userId } });

查找

await this.ctx.model.User.findAll({ where: { id: userId } });
await this.ctx.model.User.findAndCountAll({ where: { id: userId } });
await this.ctx.model.User.findOne({ where: { id: userId } });

单对单关联查询(1:1)

//model/user.js
// eg:表关联的字段,用户表和用户登录表
User.associate = function (){
  app.model.User.hasOne(app.model.UserLogin, 
  {as:'menu',sourceKey: 'uuid',foreignKey:'uuid'});   
}
//controller/user.js
let user = await ctx.model.User.findOne({
    include:{as:'menu',model:ctx.model.UserLogin},
   where:{user_number:user_number}
})

单对多关联查询(1:n)

一个菜单里有多个权限

User.associate = function (){
    app.model.Menu.hasMany(app.model.Right, 
    { as: 'rights', sourceKey: 'id', foreignKey: 'menuId' });
}

this.ctx.model.Menu.findAll({
  include: [
    {
      as: 'rights',
      model: this.ctx.model.Right,
      attributes: ['id', 'name', 'code', 'menuId'],
    },
  ],
  // 内排行
  order: [[col('rights.createdAt'), 'ASC']],
});

const rows = [
  {
    id: 1,
    name: '首页',
    rights: [
      {
        id: 1,
        name: '查看',
        code: 'read',
        menuId: 1,
      },
    ],
  },
];

多对多关联查询(n:n)

一个用户拥有多个角色
一个角色可以被很多用户拥有

// 需要一个关联表,里面有字段 userId 和 roleId
// 当删除用户或角色时,需要删除对应的关联行
app.model.Role.belongsToMany(app.model.User, { as: 'users', through: app.model.UserRoleRelation, foreignKey: 'roleId' });
app.model.User.belongsToMany(app.model.Role, { as: 'roles', through: app.model.UserRoleRelation, foreignKey: 'userId' });

const user = await this.ctx.model.User.findOne({
  include: [
    {
      model: this.ctx.model.Role,
      as: 'roles',
      through: { attributes: [] },
    },
  ],
  where: {
    id: userId,
  },
});

{
  id: "1",
  username: "admin",
  avatar: null,
  alias: "管理员",
  roles: [
    {
      id: "1",
      name: "超级管理员",
      remark: "网站总管理员,满权限",
      type: "superAdmin",
    }
  ]
}

03.总结

如果上面的都搭建完成了,那么node框架sequelize数据库就已经搭建成功啦!快去尝试吧~
看完觉得不错的话,就给点个赞吧~