sequelize 5.0中文文档 定义模型define model和验证 (二) - node.js语言最好用的orm
文章目录
前言
在使用sequelize ORM框架时一定要先创建模型对象.
对象模型对应的就是数据库中表,字段及字段类型等的定义.
我们一般的做法是先在nodejs中将对象创建出来,然后调用Sequelize的同步方法,将数据库自动创建出来.
这样就避免了既要写代码建表,又要手工创建数据库中的表的操作.
只需要单独考虑代码中的对象类型等属性就好了.
如果数据库中已经建好了表,并且不能删除,这个时候就不能自动创建了,因为创建的时候会删除掉旧的数据
定义模型
名称 | 类型 | 说明 | |
---|---|---|---|
modelName | String | 模型名,在sequelize.models属性中会使用这个名称; | |
如果没有在options中指定表名,数据库中也会使用此属性做为表名 | |||
attributes | Object | 一个对象,其每个属性对应表中的一个列, | |
每个列可以使用一个预定义的DataType、字符串或类型描述对象定义 | |||
attributes.column | String | Object 数据库中的列描述 | |
attributes.column.type | String | DataType或字符串,表示列的数据类型 | |
[attributes.column | |||
.allowNull=true] | Boolean | 设置为false时, | |
会给添加NOT NULL(非空)约束,数据保存时会进行非空验证 | |||
[attributes.column | |||
.defaultValue=null] | Any | 字面默认值, JavaScript函数, 或一个 SQL 函数 (查看 sequelize.fn) | |
[attributes.column | |||
.unique=false] | String | 设置为true时,会为列添加唯一约束 | |
[attributes.column | |||
.primaryKey=false] | Boolean | 指定是否是主键 | |
[attributes.column | |||
.field=null] | String | 设置在数据库中的字段名。 | |
设置后会,Sequelize会将属性名映射到数据库中的不同名称 | |||
[attributes.column | |||
.autoIncrement=false] | Boolean | 是否自增 | |
[attributes.column | |||
.comment=null] | String | 字段描述(自1.7+后,此描述不再添加到数据库中) | |
[attributes.column | |||
.references=null] | String | Model 引用对象 | |
[attributes.column | |||
.references.model] | String | Model 如果列引用到另一个表, | |
可以通过这个属性设置模型或字符串。 | |||
[attributes.column | |||
.references.key='id'] | String | 该列表示到表外键列的引用 | |
[attributes.column.onUpdate] | String | 当被引用的键更新时的操作, | |
可选值是:CASCADE, RESTRICT, SET DEFAULT, SET NULL 或 NO ACTION 之一 | |||
[attributes.column.onDelete] | String | 当被引用的键删除时的操作, | |
可选值是:CASCADE, RESTRICT, SET DEFAULT, SET NULL 或 NO ACTION 之一 | |||
[attributes.column.get] | Function | 为列自定义一个访问器。 | |
使用this.getDataValue(String)时调用的值 | |||
[attributes.column.set] | Function | 为列自定义一个设置器。 | |
使用this.setDataValue(String, Value)时调用的值 | |||
[attributes.validate] | Object | 模型每次保存时调用的验证对象。 | |
可是validator.js中的验证函数(参见 DAOValidator)、或自定义的验证函数。 | |||
[options] | Object | 提供给Sequelize 构造函数的一些默认值 | |
[options.defaultScope={}] | Object | 定义使用此模型的默认搜索范围。 | |
作用范围与提供给 find / findAll 的选项形式相同 | |||
[options.scopes] | Object | 更多范围,定义 defaultScope 的定义形式相同。 | |
关于限制范围的定义请参考Model.scope | |||
[options.omitNull] | Boolean | 是否忽略空值,这意味着, | |
所有列的空值将不会被保存 | |||
[options.timestamps=true] | Boolean | 为模型添加 createdAt 和 | |
updatedAt 两个时间戳字段 | |||
[options.paranoid=false] | Boolean | 使用逻辑删除。设置为true后, | |
调用 destroy 方法时将不会删队模型,而是设置一个 deletedAt 列。此设置需要 timestamps=true | |||
[options.underscored=false] | Boolean | 转换列名的驼峰命名规则为下划线命令规则 | |
[options.underscoredAll=false] | Boolean | 转换模型名的驼峰命名规则为表名的下划线命令规则 | |
[options.freezeTableName=false] | Boolean | 设置为true时, | |
sequelize不会改变表名,否则可能会按其规则有所调整 | |||
[options.name] | Object | 允有singular 和 plural两个属性的对象,在模型与其它模型关联时使用 | |
[options.name.singular= | |||
inflection.singularize(modelName)] | String | ||
[options.name.plural= | |||
inflection.pluralize(modelName)] | String | ||
[options.indexes] | Array. | 要建立的索引 | |
[options.indexes[].name] | String | 索引名,默认为模型名 + '_' + 字段名 | |
[options.indexes[].type] | String | 索引类型,仅用于 mysql, | |
其值为:UNIQUE、 FULLTEXT 或 SPATIAL之一 | |||
[options.indexes[].method] | String | 创建索引的方法(SQL中的USING 声明)。 | |
BTREE 或 HASH 可以在 mysql 和 postgres中支持,postgres中支持,还支持 GIST 和 GIN | |||
[options.indexes[].unique=false] | Boolean | 设置索引是否唯一, | |
设置后会自动触发UNIQUE设置 | |||
[options.indexes[] | |||
.concurrently=false] | Boolean | PostgreSQL 中在创建索引时不使用任务写锁定。 | |
仅 Postgres 适用 | |||
[options.indexes[].fields] | Array.<String | Object> | 建立索引的字段数组。 |
每个字段可以是一个字段名,sequelize 对象 (如 sequelize.fn),
或一个包含:attribute (字段名)、length (创建前缀字符数)、
order (列排序方向)、collate (较验的字段集合 (排序))|
|[options.createdAt] |String | 如果为字符串,
则使用提供的值代替 createdAt 列的默认名,设置为flase则不添加这个字段|
|[options.updatedAt] |String | 如果为字符串,
则使用提供的值代替 updatedAt 列的默认名,设置为flase则不添加这个字段|
|[options.deletedAt]| String | 如果为字符串,
则使用提供的值代替 deletedAt 列的默认名,设置为flase则不添加这个字段|
|[options.tableName]| String |模型所对应表的表名,
设置freezeTableName 为 true时,才会严格使用模型名|
|[options.getterMethods]| Object |提供给 getter 调用的方法,
与每列定义的访问器一样。如果为列定义了一个相同名称的 getter 方法,
那么会通过这个方法获取值;如果未定义的名称与列不匹配,
这将做为一个虚拟访问器;也用于设置多个值,但不能用在|
|[options.setterMethods] |Object |提供给 setter 调用的方法,
与每列定义的设置器一样。如果为列定义了一个相同名称的 setter 方法,
那么会通过这个方法设置值;如果未定义的名称与列不匹配,
这将做为一个虚拟访设置;也用于匹配多个值,但不用于逻辑删除|
|[options.instanceMethods]| Object| 提供给每个实例(DAO)的方法。
如果通过sequelize对方法进行了重写,可以通过"this.constructor.super_.prototype"
来调用原方法,如:this.constructor.super_.prototype.toJSON.apply(this, arguments)|
|[options.classMethods] |Object| 添加到Model的类方法,
如果通过sequelize对方法进行了重写,可以通过 this.constructor.prototype来调用原方法,
如:this.constructor.prototype.find.apply(this, arguments)|
|[options.schema='public'] |String ||
|[options.engine] |String ||
|[options.charset]| String ||
|[options.comment] |String ||
|[options.collate] |String ||
|[options.initialAutoIncrement] |String| MySQL中设置
AUTO_INCREMENT (自增)的初始值|
|[options.hooks] |Object |一个包含钩子函数的对象,
这些函数会在生生命周期内某些事件发生之前或之后被调用。
可添加的钩子函数有:beforeValidate, afterValidate, beforeBulkCreate,
beforeBulkDestroy, beforeBulkUpdate, beforeCreate, beforeDestroy,
beforeUpdate, afterCreate, afterDestroy, afterUpdate, afterBulkCreate,
afterBulkDestory 和 afterBulkUpdate。每个属性可以是一个函数,或是一个包含一组函数的数组|
|[options.validate] |Object| 模型广泛验证对象。该验证会通过this。
如果验证函数中有参数,则会被认为是异步的,并通过一个包含可选错误的回调函数形式的的调|
语法
const Department = sequelize.define('department', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING,
allowNull: false,
unique: true //定义属性同时创建索引
}
}, {
//读写属性的自定义函数,下面有单独介绍
getterMethods: {
// 自定义函数, desc() 返回部门简要信息描述
desc() {
return `${this.id} ${this.name} `;
},
},
setterMethods: {},
// classMethods 和 instanceMethods 在 版本4 被移除了
// 详见: http://docs.sequelizejs.com/manual/tutorial/upgrade-to-v4.html#config-options
// 定义 类 级别的函数,可以用 Account 调用
classMethods: {
getCMethod() {
return 'classMethods';
},
},
// 定义 实例 级别的函数,用 department 调用
instanceMethods: {
getIMethod() {
return 'instanceMethods';
},
},
// 也可以在 src/db/index 中定义全局的函数
// 设置为 false 之后,将不会自动加上 createdAt, updatedAt 这两个字段
timestamps: true,
// 假设我们需要 创建和更新 这两个字段,但不喜欢驼峰命名法
// 设置为 true 之后,自动增加的字段就会用下划线命名: created_at, updated_at
underscored: true,
// 也可以分别设置 createdAt, updatedAt 是否需要
// 假设我们喜欢 date 这个名字表示创建时间
createdAt: 'date',
// 不想要 updatedAt 这个字段
updatedAt: false,
// 设置为 true 之后,则不会真正的删除数据,而是设置 deletedAt
paranoid: true,
// 也可以重命名 deletedAt
deletedAt: 'deleteTime',
// 写表注释
comment: '账号表',
tableName: 'departments',//自定义表名,默认会生成一个 departments 的表
//统一索引设置
indexes:[
{
unique: true,
fields: ['name']//统一定义索引,和上面的属性定义索引一样的功能, 这里可以指定多个字段
},
]
});
Department.associate = (models) => {
Department.hasMany(models.Employee, {
constraints: false,
foreignKey: 'departmentId'
});
};
type 类型, 更多类型参考这里
autoIncrement 是否自增
primaryKey 是否主键
allowNull 是否可以为NULL
上面有2种定义索引的方法 可以直接属性中给 name 字段定义索引, 也可以在 indexes 数组中定义字段索引
给属性定义getter和setter函数
可以在模型上定义'对象属性'getter和setter函数,这些可以用于映射到数据库字段的“保护”属性,也可以用于定义“伪”属性.
Getters和Setters可以通过两种方式定义(您可以混合使用这两种方式)
- 作为属性定义的一部分
- 作为模型参数的一部分
注意: 如果在两个地方定义了getter或setter,那么在相关属性定义中找到的函数始终是优先的
定义为属性的一部分
const Employee = sequelize.define('employee', {
name: {
type: Sequelize.STRING,
allowNull: false,
get() {
const title = this.getDataValue('title');// 'this' 允许你访问实例的属性
return this.getDataValue('name') + ' (' + title + ')';
},
},
title: {
type: Sequelize.STRING,
allowNull: false,
set(val) {
this.setDataValue('title', val.toUpperCase());
}
}
});
我们看下效果:
Employee
.create({ name: 'John Doe', title: 'senior engineer' })
.then(employee => {
console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
console.log(employee.get('title')); // SENIOR ENGINEER
})
定义为模型的一部分
属性的getter 和 setter 为对象上定义的伪属性 - 这些属性实际上不是数据库模式的一部分
const People = sequelize.define('people', {
firstname: Sequelize.STRING,
lastname: Sequelize.STRING
}, {
getterMethods: {
fullName() {
return this.firstname + ' ' + this.lastname
}
},
setterMethods: {
fullName(value) {
const names = value.split(' ');
this.setDataValue('firstname', names.slice(0, -1).join(' '));
this.setDataValue('lastname', names.slice(-1).join(' '));
},
}
});
用于getter和setter定义内部的Helper方法
检索底层属性值 - 总是使用 this.getDataValue()
/* 一个用于 'title' 属性的 getter */
get() {
return this.getDataValue('title')
}
设置基础属性值 - 总是使用 this.setDataValue()
/* 一个用于 'title' 属性的 setter */
set(title) {
this.setDataValue('title', title.toString().toLowerCase());
}
注意: 坚持使用 setDataValue() 和 getDataValue() 函数(而不是直接访问底层的“数据值”属性)是非常重要的 - 这样做可以保护您的定制getter和setter不受底层模型实现的变化
验证
模型验证,允许您为模型的每个属性指定格式/内容/继承验证。
验证会自动运行在 create , update 和 save 上。 你也可以调用 validate() 手动验证一个实例
验证由 validator.js 实现
const ValidateMe = sequelize.define('foo', {
foo: {
type: Sequelize.STRING,
validate: {
is: ["^[a-z]+$",'i'], // 只允许字母
is: /^[a-z]+$/i, // 与上一个示例相同,使用了真正的正则表达式
not: ["[a-z]",'i'], // 不允许字母
isEmail: true, // 检查邮件格式 (foo@bar.com)
isUrl: true, // 检查连接格式 (http://foo.com)
isIP: true, // 检查 IPv4 (129.89.23.1) 或 IPv6 格式
isIPv4: true, // 检查 IPv4 (129.89.23.1) 格式
isIPv6: true, // 检查 IPv6 格式
isAlpha: true, // 只允许字母
isAlphanumeric: true, // 只允许使用字母数字
isNumeric: true, // 只允许数字
isInt: true, // 检查是否为有效整数
isFloat: true, // 检查是否为有效浮点数
isDecimal: true, // 检查是否为任意数字
isLowercase: true, // 检查是否为小写
isUppercase: true, // 检查是否为大写
notNull: true, // 不允许为空
isNull: true, // 只允许为空
notEmpty: true, // 不允许空字符串
equals: 'specific value', // 只允许一个特定值
contains: 'foo', // 检查是否包含特定的子字符串
notIn: [['foo', 'bar']], // 检查是否值不是其中之一
isIn: [['foo', 'bar']], // 检查是否值是其中之一
notContains: 'bar', // 不允许包含特定的子字符串
len: [2,10], // 只允许长度在2到10之间的值
isUUID: 4, // 只允许uuids
isDate: true, // 只允许日期字符串
isAfter: "2011-11-05", // 只允许在特定日期之后的日期字符串
isBefore: "2011-11-05", // 只允许在特定日期之前的日期字符串
max: 23, // 只允许值 <= 23
min: 23, // 只允许值 >= 23
isCreditCard: true, // 检查有效的信用卡号码
// 也可以自定义验证:
isEven(value) {
if (parseInt(value) % 2 != 0) {
throw new Error('Only even values are allowed!')
// 我们也在模型的上下文中,所以如果它存在的话,
// this.otherField会得到otherField的值。
}
}
}
}
});
请注意,如果需要将多个参数传递给内置的验证函数,则要传递的参数必须位于数组中. 但是,如果要传递单个数组参数,例如isIn的可接受字符串数组,则将被解释为多个字符串参数,而不是一个数组参数. 要解决这个问题,传递一个单一长度的参数数组,比如[['one','two']]
要使用自定义错误消息,而不是由validator.js提供,使用对象,而不是明文或参数数组,例如不需要任何参数可以给出一个自定义消息验证程序
isInt: {
msg: "Must be an integer number of pennies"
}
或者需要传递多个参数
isIn: {
args: [['en', 'zh']],
msg: "Must be English or Chinese"
}
当使用自定义的验证功能,该错误信息将是任何消息抛出Error对象持有。
查看 validator.js project 了解内置验证方法的更多细节
提示:您还可以定义日志部分自定义函数。只是传递一个函数。第一个参数将被记录。
认证器和allowNull
如果模型的列被设置为 allowNull:true 和 值被设置为 null的话,那认证器不会运行.
举个栗子, 一个字符串的列长度设置为 最短为5, 但它可以存储 null
模型认证
var Pub = Sequelize.define('pub', {
name: { type: Sequelize.STRING },
address: { type: Sequelize.STRING },
latitude: {
type: Sequelize.INTEGER,
allowNull: true,
defaultValue: null,
validate: { min: -90, max: 90 }
},
longitude: {
type: Sequelize.INTEGER,
allowNull: true,
defaultValue: null,
validate: { min: -180, max: 180 }
},
}, {
//在这里对模型进行验证,只有 latitude 和 longtitude 同时被给予或都为空时成立
validate: {
bothCoordsOrNone: function() {
if ((this.latitude === null) !== (this.longitude === null)) {
throw new Error('Require either both latitude and longitude or neither')
}
}
}
})
出自:sequelize 5.0中文文档 定义模型define model和验证 (二) - node.js语言最好用的orm