sequelize 5.0中文文档 对象实例操作与数据持久化 (五) - node.js语言最好用的orm
文章目录
前言
在面向对象语言中,我们很容易理解对象及对象的实例,
但是sequelize ORM框架中我们通常会说成模型和实例.
模型可以理解为对一个表结构的抽象定义,好比工厂的一条流水线,
实例可以理解为表结构中一个具体的数据结构,好比流水线生产出来的一个商品.
在sequelize 类中有一些api是针对实例操作 (可以理解成内存中的改变)
实例持久化以后,数据才写入我们物理存储单元中 (比如具体的数据库)
新建实例并持久化
定义模型
const Task = sequelize.define('task', {
title: Sequelize.STRING,
rating: { type: Sequelize.STRING, defaultValue: 3 }
})
构建实例
构建非持久化实例
const task = Task.build({title: 'very important task'});
task.title // ==> 'very important task'
task.rating // ==> 3,没有声明的值将设置为默认值
save持久化
为了持久化存储在数据库中,使用save方法.
task.save().catch(error => {
// mhhh, wth!
})
链式写法
Task
.build({ title: 'test' })
.save()
.then(anotherTask => {
// 持久化成功
})
.catch(error => {
// 捕捉错误
})
build 构建对象
save 持久化对象
create持久化
我们日常持久化实例都用create,
调用此api,相当于走了2步:
- 定义实例
- 实例持久化
Task.create({ title: 'new title' }).then(task => {
//构建了新实例,同时持久化到数据库
})
create持久化只会持久化模型中定义的属性,非定义属性自动抛弃
例如:
Task.create({ title: 'new title',desc:'xxxxxxxx' }).then(task => {
//新实例持久化到数据库中的属性只有 title
})
未定义的属性 desc,并没有持久化成功.
更新实例并持久化
当我们需要对实例更改时,
如何将更改后的实例持久化.
save更新实例
task.title = 'update title'
task.save().then(() => {})
update更新实例
task.update({
title: 'a very different title now'
}).then(() => {})
save 等价于 update,
未被定义的属性都将不能持久化.
destroy移除实例
Task.create({ title: 'destroy task' }).then(task => {
//task就是该对象的引用
return task.destroy();//然后就能够通过引用调用destroy方法删除它
}).then(() => {
// 捕捉错误
})
也可以直接用实例的 destroy 方法,将对应的实例移除
Task.destroy({title:'destroy task'}).then(()=>{
//实例移除成功
});
一次执行多个实例操作
除了更新单个实例,你也可以一次create, update, and delete多个实例.
当你执行的是多个模型,回调将不会返回DAO实例.
BulkCreate将返回模型实例/DAOs数组,不像create,没有自动增长属性的结果值.
update和destroy将返回被影响的行的数量.
Model.bulkCreate
批量创建
User.bulkCreate([
{ username: 'barfooz', isAdmin: true },
{ username: 'foo', isAdmin: true },
{ username: 'bar', isAdmin: false }
]).then(() => { // Notice: There are no arguments here, as of right now you'll have to...
return User.findAll();
}).then(users => {
console.log(users) // ... in order to get the array of user objects
})
bulkCreate通过添加validate: true属性,添加实例时将会去验证
const Tasks = sequelize.define('task', {
name: {
type: Sequelize.STRING,
validate: {
notNull: { args: true, msg: 'name 不能为null' }
}
},
code: {
type: Sequelize.STRING,
validate: {
len: [3, 10]
}
}
})
Tasks.bulkCreate([
{name: 'foo', code: '123'},
{code: '1234'},//失败,因为name不能为null
{name: 'bar', code: '1'}//失败,code长度小于3
], { validate: true }).catch(errors => {
/* console.log(errors) would look like:
[
{ record:
...
name: 'SequelizeBulkRecordError',
message: 'Validation error',
errors:
{ name: 'SequelizeValidationError',
message: 'Validation error',
errors: [Object] } },
{ record:
...
name: 'SequelizeBulkRecordError',
message: 'Validation error',
errors:
{ name: 'SequelizeValidationError',
message: 'Validation error',
errors: [Object] } }
]
*/
})
Model. update
批量更新
Task.bulkCreate([
{subject: 'programming', status: 'executing'},
{subject: 'reading', status: 'executing'},
{subject: 'programming', status: 'finished'}
]).then(() => {
return Task.update(
{ status: 'inactive' }, /* set attributes' value */
{ where: { subject: 'programming' }} /* where criteria */
);
}).spread((affectedCount, affectedRows) => {
// 批量更新2条数据后,返回结果 spread 来接收返回值,自动拆分成2部分(见下方spread的说明)
// affectedCount will be 2
return Task.findAll();
}).then(tasks => {
console.log(tasks) // the 'programming' tasks will both have a status of 'inactive'
})
注意:
上面 update 方法后使用 spread 方法来接收更新后的数据参数,
为什么不是 then ?
spread介绍
spread 的功能类似then,但是它有一个优点,可以把回调得到的数据拆分成2部分,
什么时候拆分
比如上面的 update 方法,
当你使用 postgresql数据库时,
当你设置update方法的 options.returning=true时,
执行成功后返回的结果集包含2部分
- 影响的行数
- 影响的数据
当返回结果如上包含2部分时,sequelize 提供的 spread 方法可以拆分这2部分,
常用的方法还有 findOrCreate
User
.findOrCreate({where: {username: 'sdepold'}, defaults: {job: 'Technical Lead JavaScript'}})
.spread((user, created) => {
console.log(user.get({
plain: true
}))
console.log(created)
/*
findOrCreate 返回一个包含已找到或创建的对象的数组,找到或创建的对象和一个布尔值,如果创建一个新对象将为true,否则为false,像这样:
[ {
username: 'sdepold',
job: 'Technical Lead JavaScript',
id: 1,
createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),
updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)
},
true ]
在上面的例子中,".spread" 将数组分成2部分,并将它们作为参数传递给回调函数,在这种情况下将它们视为 "user" 和 "created" 。(所以“user”将是返回数组的索引0的对象,并且 "created" 将等于 "true"。)
*/
})
Model. destroy
批量删除
Task.bulkCreate([
{subject: 'programming', status: 'executing'},
{subject: 'reading', status: 'executing'},
{subject: 'programming', status: 'finished'}
]).then(() => {
return Task.destroy({
where: {
subject: 'programming'
},
truncate: true /* this will ignore where and truncate the table instead */
});
}).then(affectedRows => {
// 影响的行数 2
return Task.findAll();
}).then(tasks => {
console.log(tasks) // no programming, just reading :(
})
批量创建后然后批量删除.
Reloading重载实例
如果你想要同步得到你的实例,你可以使用方法reload重载.
他将从数据库获取当前的数据并覆写之前调用过方法的模型的属性(不改变数据库中原来属性值)
Person.findOne({ where: { name: 'john' } }).then(person => {
person.name = 'jane'
console.log(person.name) // 'jane'
person.reload().then(() => {
console.log(person.name) // 'john' 重载后 name 已经变成 john ,但是数据库中此记录的 name值依然是 jane
})
})
递增和递减整数值
为了递增/递减实例的值而不会遇到并发问题,Sequelize提供了 increment 和 decrement 实例方法.
const jane = await User.create({ name: "Jane", age: 100 });
const incrementResult = await user.increment('age', { by: 2 });
// 注意: 如只增加 1, 你可以省略 'by' 参数, 只需执行 `user.increment('age')`
// 在 PostgreSQL 中, 除非设置了 `{returning:false}` 参数(不然它将是 undefined),
// 否则 `incrementResult` 将是更新后的 user.
// 在其它数据库方言中, `incrementResult` 将会是 undefined. 如果你需要更新的实例, 你需要调用 `user.reload()`.
你也可以一次递增多个字段
const jane = await User.create({ name: "Jane", age: 100, cash: 5000 });
await jane.increment({
'age': 2,
'cash': 100
});
// 如果值增加相同的数量,则也可以使用以下其他语法:
await jane.increment(['age', 'cash'], { by: 2 });