建立Model
直接使用Sequelize虽然可以,但是存在一些问题。
团队开发时,有人喜欢自己加timestamp:
var Pet = sequelize.define('pet', {
id: {
type: Sequelize.STRING(50),
primaryKey: true
},
name: Sequelize.STRING(100),
createdAt: Sequelize.BIGINT,
updatedAt: Sequelize.BIGINT
}, {
timestamps: false
});
有人又喜欢自增主键,并且自定义表名:
var Pet = sequelize.define('pet', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: Sequelize.STRING(100)
}, {
tableName: 't_pet'
});
一个大型Web App通常都有几十个映射表,一个映射表就是一个Model。如果按照各自喜好,那业务代码就不好写。Model不统一,很多代码也无法复用。
所以我们需要一个统一的模型,强迫所有Model都遵守同一个规范,这样不但实现简单,而且容易统一风格。
Model
我们首先要定义的就是Model存放的文件夹必须在models
内,并且以Model名字命名,例如:Pet.js
,User.js
等等。
其次,每个Model必须遵守一套规范:
- 统一主键,名称必须是
id
,类型必须是STRING(50)
; - 主键可以自己指定,也可以由框架自动生成(如果为null或undefined);
- 所有字段默认为
NOT NULL
,除非显式指定; - 统一timestamp机制,每个Model必须有
createdAt
、updatedAt
和version
,分别记录创建时间、修改时间和版本号。其中,createdAt
和updatedAt
以BIGINT
存储时间戳,最大的好处是无需处理时区,排序方便。version
每次修改时自增。
所以,我们不要直接使用Sequelize的API,而是通过db.js
间接地定义Model。例如,User.js
应该定义如下:
const db = require('../db'); module.exports = db.defineModel('users', {
email: {
type: db.STRING(100),
unique: true
},
passwd: db.STRING(100),
name: db.STRING(100),
gender: db.BOOLEAN
});
这样,User就具有email
、passwd
、name
和gender
这4个业务字段。id
、createdAt
、updatedAt
和version
应该自动加上,而不是每个Model都去重复定义。
所以,db.js
的作用就是统一Model的定义:
const Sequelize = require('sequelize'); console.log('init sequelize...'); var sequelize = new Sequelize('dbname', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
pool: {
max: 5,
min: 0,
idle: 10000
}
}); const ID_TYPE = Sequelize.STRING(50); function defineModel(name, attributes) {
var attrs = {};
for (let key in attributes) {
let value = attributes[key];
if (typeof value === 'object' && value['type']) {
value.allowNull = value.allowNull || false;
attrs[key] = value;
} else {
attrs[key] = {
type: value,
allowNull: false
};
}
}
attrs.id = {
type: ID_TYPE,
primaryKey: true
};
attrs.createdAt = {
type: Sequelize.BIGINT,
allowNull: false
};
attrs.updatedAt = {
type: Sequelize.BIGINT,
allowNull: false
};
attrs.version = {
type: Sequelize.BIGINT,
allowNull: false
};
return sequelize.define(name, attrs, {
tableName: name,
timestamps: false,
hooks: {
beforeValidate: function (obj) {
let now = Date.now();
if (obj.isNewRecord) {
if (!obj.id) {
obj.id = generateId();
}
obj.createdAt = now;
obj.updatedAt = now;
obj.version = 0;
} else {
obj.updatedAt = Date.now();
obj.version++;
}
}
}
});
}
我们定义的defineModel
就是为了强制实现上述规则。
Sequelize在创建、修改Entity时会调用我们指定的函数,这些函数通过hooks
在定义Model时设定。我们在beforeValidate
这个事件中根据是否是isNewRecord
设置主键(如果主键为null
或undefined
)、设置时间戳和版本号。
这么一来,Model定义的时候就可以大大简化。
数据库配置
接下来,我们把简单的config.js拆成3个配置文件: config-default.js:存储默认的配置;
config-override.js:存储特定的配置;
config-test.js:存储用于测试的配置。
例如,默认的config-default.js可以配置如下:
var config = {
dialect: 'mysql',
database: 'nodejs',
username: 'www',
password: 'www',
host: 'localhost',
port: 3306
}; module.exports = config;
而config-override.js
可应用实际配置:
var config = {
database: 'production',
username: 'www',
password: 'secret-password',
host: '192.168.1.199'
}; module.exports = config;
config-test.js
可应用测试环境的配置:
var config = {
database: 'test'
}; module.exports = config;
读取配置的时候,我们用config.js
实现不同环境读取不同的配置文件:
const defaultConfig = './config-default.js';
// 可设定为绝对路径,如 /opt/product/config-override.js
const overrideConfig = './config-override.js';
const testConfig = './config-test.js'; const fs = require('fs'); var config = null; if (process.env.NODE_ENV === 'test') {
console.log(`Load ${testConfig}...`);
config = require(testConfig);
} else {
console.log(`Load ${defaultConfig}...`);
config = require(defaultConfig);
try {
if (fs.statSync(overrideConfig).isFile()) {
console.log(`Load ${overrideConfig}...`);
config = Object.assign(config, require(overrideConfig));
}
} catch (err) {
console.log(`Cannot load ${overrideConfig}.`);
}
} module.exports = config;
具体的规则是:
- 先读取
config-default.js
; - 如果不是测试环境,就读取
config-override.js
,如果文件不存在,就忽略。 - 如果是测试环境,就读取
config-test.js
。
这样做的好处是,开发环境下,团队统一使用默认的配置,并且无需config-override.js
。部署到服务器时,由运维团队配置好config-override.js
,以覆盖config-override.js
的默认设置。测试环境下,本地和CI服务器统一使用config-test.js
,测试数据库可以反复清空,不会影响开发。
配置文件表面上写起来很容易,但是,既要保证开发效率,又要避免服务器配置文件泄漏,还要能方便地执行测试,就需要一开始搭建出好的结构,才能提升工程能力。
使用Model
建立Model的更多相关文章
- J2EE进阶(七)利用SSH框架根据数据表建立model类
J2EE进阶(七)利用SSH框架根据数据表建立model类 前言 在利用SSH框架进行项目开发时,若将数据库已经建好,并且数据表之间的依赖关系已经确定,可以利用Hibernate的反转功能进行mode ...
- SpeedPHP关于一对一和一对多关联关系的建立 model建立
新闻表:t_news 新闻类型表:b_type_to_name 其中一个新闻类型可以包含多个新闻(hasmany),一个新闻只能属于一种新闻类型(hasone) 下面是新闻model类: <?p ...
- Django根据现有数据库建立model
Django引入外部数据库还是比较方便的,步骤如下 创建一个项目,修改seting文件,在setting里面设置你要连接的数据库类型和连接名称,地址之类,和创建新项目的时候一致 运行下面代码可以自动生 ...
- thinkphp model模块
1.获取系统常量信息的方法:在控制器DengLuController里面下写入下面的方法,然后调用该方法. public function test() { //echo "这是测试的&qu ...
- 建立mvc过程
1.public class dbContext:Dbcontext { private readonly static string CONNECTION_STRING="name=d ...
- Cesium 中两种添加 model 方法的区别
概述 Cesium 中包含两种添加 model 的方法,分别为: 通过 viewer.entities.add() 函数添加 通过 viewer.scene.primitives.add() 函数添加 ...
- SQLAlchemy 使用(一)创建单一model
前言 最近项目等待前端接接口,比较空闲.就想学习一些新东西.学啥呢?考虑到ORM的易用性,还是学习一下ORM.那么与Flask搭配的ORM有 flask-sqlalchemy 但是该组件专为Flask ...
- odoo 基于SQL View视图的model类
在做odoo的过程中,会涉及到多表的查询, 尤其是做报表的时候这种情况更甚,这样下来会做很多的关联,不是很方便.odoo提供了一种机制,即基于视图的model类.代码地址在这里. 具体过程如下: 1. ...
- Ruby学习笔记4: 动态web app的建立
Ruby学习笔记4: 动态web app的建立 We will first build the Categories page. This page contains topics like Art, ...
- Backbone.js 中使用 Model
前面几篇 Backbone.js 的例子中有使用到 template, 及数据的填充,其实这已经很接近 Model 了.现在来学习怎么创建自己的 Model 类,并简单的使用.Backbone.js ...
随机推荐
- 4G LTE/EPC UE 的业务请求流程
目录 文章目录 目录 UE 发起业务请求(Service Request)流程 UE 侧发起的业务请求流程 网络侧发起的业务请求流程 UE 发起业务请求(Service Request)流程 作用:附 ...
- Asp-Net-Core开发笔记:使用ActionFilterAttribute实现非侵入式的参数校验
前言 在现代应用开发中,确保API的安全性和可靠性至关重要. 面向切面编程(AOP)通过将横切关注点(如验证.日志记录.异常处理)与核心业务逻辑分离,极大地提升了代码的模块化和可维护性. 在ASP.N ...
- Mysql 存储引擎的区别以及索引查询失效的情况
存储引擎:就是指表在计算机上的存储方式.可以通过 SHOW ENGINES; 命令查询支持的存储引擎. alter table test engine= innodb/memory/myisam/ar ...
- 多进程池Flask实战应用
多进程池Flask实战应用 import json import math import flask from concurrent.futures import ProcessPoolExecuto ...
- Pandas学习之路【3】
新增列的一些操作 1.新增一个列,直接给列赋值 # 取所有行,新增的列为new_col df.loc[:, 'new_col'] = 100 2.使用df.apply方法给新增的列赋值 def get ...
- MD5计算,一个扩展类,哪里都能用
最近有同学问到如何计算一个字节数组的MD5值,现在分享一个扩展类,有了它,MD5计算再也不用其他了. 先看示例: string s = "hello world"; var s_m ...
- Stable Diffusion WebUI详细使用指南
Stable Diffusion WebUI(AUTOMATIC1111,简称A1111)是一个为高级用户设计的图形用户界面(GUI),它提供了丰富的功能和灵活性,以满足复杂和高级的图像生成需求.由于 ...
- Xcode 自动化构建问题梳理
一.Xcode Xcode是mac OS平台上面开发的官方IDE,可以用来开发iOS应用和mac应用.随着iOS系统的升级,Xcode也会更新,而且是强制更新. Xcode每次版本更新稳定性很差,经常 ...
- fabric compose文件解读(Orderer篇)
orderer在fabric中的作用是排序,另外orderer有点像是管理节点一样,通道之类的都是在orderer的基础之上建立的,有点像比特币,以太坊上面的全节点一样,不过责任比全节点少很多,甚至都 ...
- js 生成pdf
最简洁的代码 <script src="js/html2canvas.min.js" type="text/javascript" charset=&qu ...