Egg-sequelize的使用

506 阅读4分钟

sequelize

在Egg项目中安装和使用sequelize步骤:

1.下载egg-sequelize:

npm install --save egg-sequelize mysql2
  1. 在plugin.js 文件中引入插件

    module.exports = {
    	sequelize: {
            enable: true,
            package: 'egg-sequelize'
    	}
    }
    
  2. 在config.default.js文件中配置数据库连接

    config.sequelize = {
        dialect: 'mysql',
        database: 'mysqlname',
        host: 'localhost',	
        port: 3306,
        username: 'root',
        password: '123456',
        timezone: "+08:00", //时区转换
        // 时间自动转字符串格式化
        dialectOptions: {
          dateStrings: true,
          typeCast: true,
        },
        define: {
          timestamps: true,
        }
    };
    

    MySQL数据库与sequelize数据类型对应如下

    1. STRING => varchar(255)
    2. INTEGER => int
    3. DOUBLE => double
    4. DATE => datetime
    5. TEXT => text
    
    Sequelize.STRING                      // VARCHAR(255)
    Sequelize.STRING(1234)                // VARCHAR(1234)
    Sequelize.STRING.BINARY               // VARCHAR BINARY
    Sequelize.TEXT                        // TEXT
    Sequelize.TEXT('tiny')                // TINYTEXT
     
    Sequelize.INTEGER                     // INTEGER
    Sequelize.BIGINT                      // BIGINT
    Sequelize.BIGINT(11)                  // BIGINT(11)
     
    Sequelize.FLOAT                       // FLOAT
    Sequelize.FLOAT(11)                   // FLOAT(11)
    Sequelize.FLOAT(11, 12)               // FLOAT(11,12)
     
    Sequelize.DOUBLE                      // DOUBLE
    Sequelize.DOUBLE(11)                  // DOUBLE(11)
    Sequelize.DOUBLE(11, 12)              // DOUBLE(11,12)
     
    Sequelize.DECIMAL                     // DECIMAL
    Sequelize.DECIMAL(10, 2)              // DECIMAL(10,2)
     
    Sequelize.DATE                        // DATETIME
    Sequelize.DATE(6)                     // DATETIME(6) 小数秒支持6位精度
    Sequelize.DATEONLY                    // DATE 不带时间
    Sequelize.BOOLEAN                     // TINYINT(1)
    
  3. 在app/model文件中创建数据库模型

    在app/model目录中创建clazz.js文件,对应数据库中的clazz表

    module.exports = app => {
        const { STRING } = app.Sequelize;
        // 默认情况下,sequelize将自动将所有传递的模型名称(define的第一个参数)转换为复数
        const Clazz =  app.model.define('clazz', {
        	name: STRING,
        })
        return Clazz;
    }
    
  4. 添加app.js文件,初始化数据库

    在项目根目录中创建app.js文件,初始化数据库

    module.exports = app => {
    	app.beforeStart(async function() {
    		// 开发环境使用,会删除数据表
    		// await app.model.sync({ force: true });
    		await app.model.sync({});
    	});
    };
    

    在controller中实现数据的增删改查

    说明: 在真实的项目中,controller和操作数据的逻辑要分离,以便项目的扩展与维护。

    // 查询数据
    this.app.model.Clazz.findAll(); 
    // 通过id查询
    this.app.model.Clazz.findByPk(1); 
    // 通过wherre设置查询条件
    this.app.model.Clazz.findOne({ where: { id: 1 } });
    // 添加数据
    this.app.model.Clazz.create({ name: "xx" });
    // 通过条件修改数据
    this.app.model.Clazz.update({ name: "xx" }, { where: { id: 1} });
    // 通过条件删除数据
    this.app.model.Clazz.destroy({ where: { id: 1 } });
    

    在Student与clazz之间一对多和多对一的表关联

    1. 创建一个名为clazz的班级表,包含id和name两个字段
    module.exports = (app) => {
      const { STRING, INTEGER, BOOLEAN } = app.Sequelize;
    
      const Clazz = app.model.define("clazz", {
        id: {
          type: INTEGER,
          autoIncrement: true,
          primaryKey: true,
        },
        name: {
          type: STRING,
          allowNull: false,
        },
      });
    
      // 建立联系
      Clazz.associate = function () {
        // 课程和学生一对多,用hasmany,用学生的clazz_id作为外键参考,和自己的id字段匹配
        // clazz 有很多 Student, clazz当作是集合(主),student当作是元素(次)
        // 知道主次就能较好的记忆了
        // targetKey当作是班级牌号,foreignKey当作是学生找班牌号的参考
        // 理解成把学生按照什么分类到班级里去,就稍微好记一点
        app.model.Clazz.hasMany(app.model.Student, {
          foreignKey: "clazz_id",
          targetKey: "id",
        });
      };
    
      return Clazz;
    };
    
    1. 学生的模型
    // student.js
    "use strict";
    
    module.exports = (app) => {
      const { STRING, INTEGER } = app.Sequelize;
    
      const Student = app.model.define("student", {
        id: {
          type: INTEGER,
          autoIncrement: true,
          primaryKey: true,
        },
        clazzId: {
          type: INTEGER,
          allowNull: false,
        },
        name: {
          type: STRING(16),
          allowNull: false,
        },
      });
    
      Student.associate = function () {
        // 学生与班级是多对一, belongsTo属于谁
        // 学生属于班级,学生是次,班级是主,foreignKey在学生里面找,targetKey在班级找
        app.model.Student.belongsTo(app.model.Clazz, {
          foreignKey: "clazzId",
          targetKey: "id",
        });
      };
      return Student;
    };
    
    
    总结:
    1. 先确定表之间的关系
    2. 表一和表二是一对多的话建立联系的时候在模型里面是

      表一模型.associate = function(){
          表一模型.hasMany(表二模型,{ foreignKey: 次的字段,targetKey: 主的字段 })
      }
      
    3. 表二和表一建立链接的时候就是belongsTo

      表二模型.associate = function(){
          表二模型.belongsTo(表一模型,{ foreignKey: 次的字段,targetKey: 主的字段 })
      }
      
    4. 分清楚主次,上面可以看出表一是主,表二是次
    5. 通式化:

      表一模型.hasMany(表二模型,{ foreignKey: 表二的字段,targetKey: 表一的字段 })
      表二模型.belongsTo(表一模型,{ foreignKey: 表二的字段,targetKey: 表一的字段 })
      
    6. 如果是一对一(主次可调换) ,由上可得
      表一模型.hasOne(表二模型,{ foreignKey: 表二的字段,targetKey: 表一的字段 })
      表二模型.belongsTo(表一模型,{ foreignKey: 表二的字段,targetKey: 表一的字段 })
      
    多对多

    多对多: 学生和老师,一个老师有多个学生,一个学生有多个老师 要确定某条数据需要同时确定学生和老师的关系 一般需要第三张表进行记录,比如把某个学生的id和某个老师的id组合当成一行数据记录,来确定

    代码简写如下

    student.js

    Student.associate = function (){
            // 与Teacher存在多对多关系,使用belongsToMany()
            app.model.Student.belongsToMany(app.model.Teacher, {
            	// 通过TeacherStudent模型对应的表查询
            	// foreignKey和Student匹配的值,再匹配otherKey的值
            	// 例如: student表的id和TeacherStudent表的studentId匹配上了
            	// 然后得到teacherId去和teacher表匹配得到的结果就是这个id的学生的老师
                through: app.model.TeacherStudent,
                // 注意驼峰还是下划线,
                // 模型配置里面underscored默认为true,把驼峰转换为下划线
                foreignKey: 'studentId', //这两个字段是主键或者是外键类型和两张表对应
                otherKey: 'teacherId'
            });
        }
    return Student;
    

    teacher.js

    Teacher.associate = function(){
            app.model.Teacher.belongsToMany(app.model.Student, {
                through: app.model.TeacherStudent,
                foreignKey: 'teacherId',
                otherKey: 'studentId'
            });
        }
    return Teacher;
    

    teacherStudent.js

    TeacherStudent.associate = function(){}
    
    return TeacherStudent;
    
    contro.js
    // contro.js
    async info(){
    		const { ctx, app } = this;
    		//学生有哪些老师
    		let result = await app.m.Student.findAll({
    		  include: {
    			  model: app.m.Teacher
    		  }
    		  
    		});
    		ctx.body = result;
    
    		// 每个老师有哪些学生
    		// let result = await app.m.Teacher.findAll({
    		//   include: {
    		// 	  model: app.m.Student
    		//   }
    		  
    		// });
    		// ctx.body = result;
    	}
    
    总结:

    多对多是固定的格式

    表一模型.belongsToMany(表二模型, {
        through: 中间表模型,
        foreignKey: '在中间表里面和表一匹配的字段',
        otherKey: '在中间表里面和表二匹配的字段'
    });
    查询还是
    await app.m.Student.findAll({
    	include: {
    		model: app.m.Teacher
    	 }
    });
    

定义 service

在app/servicr目录下创建student.js文件

const Service = require('egg').Service;
class StudentService extends Service {
    async getStudentList() {
        // orm操作
    }
}

module.exports = StudentService;