5. 实例的使用、Instance类介绍
Instance
类表示数据库中的一行记录,该类不能直接实例化,而应该由Model
对象创建。Instance
实例有两种,由Model.build
方法创建的非持久化实例,和由Model.create
方法创建的持久化实例。应该注意,Instance
翻译后也叫做“实例”,但它在Sequelize 中是一个类,它的实例应该叫做“实例”类的实例。
- 实例的创建与使用
- 1.1 构建非持久化实例
- 1.2 创建持久化实例
- 1.3 实例的更新/保存/持久化
- 1.4 删除持久化实例
- 1.5 批量操作
- 1.6 实例值
- 1.7 实例的重新加载
- 1.8 实例字段值的增大
- 1.9 实例字段值的减小
- 2.
Instance
类的API- 2.1
isNewRecord
- 是否新记录 - 2.2
Model()
- 创建实例的模型 - 2.3
sequelize()
- Sequelize实例 - 2.4
where()
- 实例的查询条件 - 2.5
getDataValue()
- 获取值 - 2.6
setDataValue()
- 设置值 - 2.7
get()
- 获取值(单个或全部) - 2.8
set()
- 设置值 - 2.9
changed()
- 判断是否修改 - 2.10
previous()
- 返回修改前的值 - 2.11
save()
- 保存实例到数据库 - 2.12
reload()
- 重新加载数据 - 2.13
validate()
- 验证属性 - 2.14
update()
- 设置并保存 - 2.15
destroy()
- 删除 - 2.16
restore()
- 数据恢复 - 2.17
increment()
- 字段值增加 - 2.18
decrement()
- 字段值减小 - 2.19
equals()
- 实例值是否相等 - 2.20
equalsOneOf()
- 实例值其中的一个相等 - 2.21
toJSON()
- 转换成JSON
- 2.1
1. 实例的创建与使用
1.1 构建非持久化实例
为了创建定义类的实例,需要像下面这样做。使用build
方法会返回一个未保存的对象,你应该显式的调用save
方法保存。
var project = Project.build({ title: '这是一个项目', description: '项目的描述,来自:itbilu.com' }) var task = Task.build({ title: 'specify the project idea', description: 'bla', dea
构建的实例会自动获取我们定义的默认值:
// 先定义模型 var Task = sequelize.define('task', { title: Sequelize.STRING, rating: { type: Sequelize.STRING, defaultValue: 3 } }) // build 构建一个实例 var task = Task.build({title: 'very important task'}) task.title // ==> 'very important task' task.rating // ==> 3
要将构建非持久实例保存到数据库中,需要使用use
方法:
project.save().then(function() { // 保存后的回调 }) task.save().catch(function(error) { // mhhh, wth! }) // 也可以链式的build构建实例,再you can also build, save and access the object with chaining: Task .build({ title: 'foo', description: 'bar', deadline: new Date() }) .save() .then(function(anotherTask) { // 现在可以通过anotherTask变量,访问已保存的 task }).catch(function(error) { // Ooops, 错误处理 })
1.2 创建持久化实例
除了显式的调用save
方法保存实例外,还可以create
方法创建并保存实例。
Task.create({ title: 'foo', description: 'bar', deadline: new Date() }).then(function(task) { // 现在可以通过 task 变量访问新创建的 Task })
1.3 实例的更新/保存/持久化
修改实例的一些值,并保存到数据库可以通过以下两种方式实现:
// 方法 1 task.title = 'a very different title now' task.save().then(function() {}) // 方法 2 task.update({ title: 'a very different title now' }).then(function() {})
可样可以设置哪些属性需要保存,传入一个包含字段名的数组即可。
task.title = 'foooo' task.description = 'baaaaaar' task.save({fields: ['title']}).then(function() { // 现在 title 是 'foooo' 但是 description 还是和以前一样 }) // 同样可以使用 update 方法进行保存: task.update({ title: 'foooo', description: 'baaaaaar'}, {fields: ['title']}).then(function() { // 现在 title 是 'foooo' 但是 description 还是和以前一样 })
当调用save
但不做任何修改时,该方法不会做任何操作。
1.4 删除持久化实例
创建对象并获取对象引用后,可以通过destroy
方法将其从数据库中删除:
Task.create({ title: 'a task' }).then(function(task) { // 这样删除... return task.destroy(); }).then(function() { // 删除完成 :) })
1.5 批量操作
除更新单个实例外,还可以创建、更新和删除多个实例。批量操作的方法有:
Model.bulkCreate
Model.update
Model.destroy
当操作多个模型时,回调中不会返回DAO 实例。bulkCreate
会一个包含多个实例/DAO的数组,但不像create
,结果中没有自增属性。而update
和destroy
会返回受影响的行数。
批量创建操作:
User.bulkCreate([ { username: 'barfooz', isAdmin: true }, { username: 'foo', isAdmin: true }, { username: 'bar', isAdmin: false } ]).then(function() { // Notice: There are no arguments here, as of right now you'll have to... return User.findAll(); }).then(function(users) { console.log(users) // ... in order to get the array of user objects })
更新多条数据:
Task.bulkCreate([ {subject: 'programming', status: 'executing'}, {subject: 'reading', status: 'executing'}, {subject: 'programming', status: 'finished'} ]).then(function() { return Task.update( { status: 'inactive' }, /* set attributes' value */, { where: { subject: 'programming' }} /* where criteria */ ); }).spread(function(affectedCount, affectedRows) { // .update 会返会一个包含两个值的数组,使用 .spread展开 // 注意,只有支持 returning: true属性的数据库才会返回 affectedRows // affectedCount 是 2 return Task.findAll(); }).then(function(tasks) { console.log(tasks) // subject为 'programming' 的对象的 status属性会更新为 'inactive' })
删除多条数据:
Task.bulkCreate([ {subject: 'programming', status: 'executing'}, {subject: 'reading', status: 'executing'}, {subject: 'programming', status: 'finished'} ]).then(function() { return Task.destroy({ where: { subject: 'programming' }, truncate: true /* 这会对表使用truncate(截断)操作,并忽略where条件 */ }); }).then(function(affectedRows) { // affectedRows 是2 2 return Task.findAll(); }).then(function(tasks) { console.log(tasks) // 没有 programming, 也没有 reading :( })
如果你是从用户输入接收值,那可想要设置要插入的值。bulkCreate()
接受第二个参数对象,你可以在其中传入一个fields
(数组)参数,以表示哪些字段需要插入。
User.bulkCreate([ { username: 'foo' }, { username: 'bar', admin: true} ], { fields: ['username'] }).then(function() { // nope bar, you can't be admin! })
bulkCreate
是一种快速的插入数据的方式,但在插入多行数据时,我们又不希望牺牲模型验证,这时可以通过validate
参数告诉Sequelize只有通过筛选的数据才能插入数据库。
var Tasks = sequelize.define('task', { name: { type: Sequelize.STRING, validate: { notNull: { args: true, msg: 'name cannot be null' } } }, code: { type: Sequelize.STRING, validate: { len: [3, 10] } } }) Tasks.bulkCreate([ {name: 'foo', code: '123'}, {code: '1234'}, {name: 'bar', code: '1'} ], { validate: true }).catch(function(errors) { /* console.log(errors) would look like: [ { record: ... errors: { name: 'SequelizeValidationError', message: 'Validation error', errors: [Object] } }, { record: ... errors: { name: 'SequelizeValidationError', message: 'Validation error', errors: [Object] } } ] */ })
1.6 实例值
当我们打印实例时,会看到很多额外的值。为了隐藏这些东西,可以使用get
-属性,并使用plain = true
选项来返回实例值。
Person.create({ name: 'Rambow', firstname: 'John' }).then(function(john) { console.log(john.get({ plain: true })) }) // result: // { name: 'Rambow', // firstname: 'John', // id: 1, // createdAt: Tue, 01 May 2012 19:12:16 GMT, // updatedAt: Tue, 01 May 2012 19:12:16 GMT // }
1.7 实例的重新加载
实例中有一个reload
方法,该方法会同步数据中的当前的数据,并使用刚加载的数据对模型属性进行重写。
Person.findOne({ where: { name: 'john' } }).then(function(person) { person.name = 'jane' console.log(person.name) // 'jane' person.reload().then(function() { console.log(person.name) // 'john' }) })
1.8 实例字段值的增大
increment
方法,可以为实例属性(字段)增加一个确定义的字面值,该方法直接单个或多个字段属性值的增加。
为一个属性增加值:
User.findById(1).then(function(user) { return user.increment('my-integer-field', {by: 2}) }).then(/* ... */)
为多个属性增加值:
User.findById(1).then(function(user) { return user.increment([ 'my-integer-field', 'my-very-other-field' ], {by: 2}) }).then(/* ... */)
也可以使用对象的形式为多个属性增加值:
User.findById(1).then(function(user) { return user.increment({ 'my-integer-field': 2, 'my-very-other-field': 3 }) }).then(/* ... */)
1.9 实例字段值的减小
我们可以向increment
方法传入一个负数来减小字段值。相对应的,还有一个decrement
方法,该方法用于减小字段值:
为一个属性减小值:
User.findById(1).then(function(user) { return user.decrement('my-integer-field', {by: 2}) }).then(/* ... */)
为多个属性减小值:
User.findById(1).then(function(user) { return user.decrement([ 'my-integer-field', 'my-very-other-field' ], {by: 2}) }).then(/* ... */)
也可以使用对象的形式为多个属性减小值:
User.findById(1).then(function(user) { return user.decrement({ 'my-integer-field': 2, 'my-very-other-field': 3 }) }).then(/* ... */)
更多关于increment
、increment
的使用请参考:
单实例字段的自增、自减
2. Instance
类的API
Instance
类表示一个实例,表示数据库中的一行。它不能通过构造函数实例化,而应该通过Model.find*或Model.create等方法创建。
实例中包含一个dataValues
属性,其中存储了实例实际所要操作的值。dataValues
中的值可以通过以下几种方式访问:
instance.field // 等价于 instance.get('field') // 等价于 instance.getDataValue('field')
如果定义了访问器(getter)/设置器(setter),字段值从其中访问而不是从dataValues
。一般会直接访问或使用get
来访问属性值,而getDataValue
只用于自定义的访问器。
相关
- Sequelize#define
2.1 isNewRecord
- 是否新记录
instance.isNewRecord -> Boolean
当实例是未保存到数据库的非持久化实例时,返回true
2.2 Model()
- 创建实例的模型
instance.Model() -> Model
返回创建实例的Model
。
相关
- Model
2.3 sequelize()
- Sequelize实例
instance.sequelize() -> Sequelize
返回Sequelize实例的引用
相关
- Sequelize
2.4 where()
- 实例的查询条件
instance.where() -> Object
获取当前实例的查询条件,相当于option.where
2.5 getDataValue()
- 获取值
instance.getDataValue(key) -> any
获取底层数据值。
key
- {String},表示要获取值的字段名
2.6 setDataValue()
- 设置值
instance.setDataValue(key, value)
设置底层数据值。
key
- {String},表示要设置值的字段名value
- {any},表示要设置的值
2.7 get()
- 获取值(单个或全部)
instance.get([key], [options]) -> Object|any
不提供key
时,返回全部实例值。同样适用于虚拟访问器。
提供key
时,返回字段值或返回虚拟访问器的值。
[key]
- {String},表示要访问值的字段名[options]
- {Object}[options.plain=false]
- {Boolean},设置为true时,返回简单对象
2.8 set()
- 设置值
instance.set(key, value, [options])
set
用于更新实例值。set
更新的值会保存在底层的dataValues
对象中,如果为所设置的key
设置了自定义设置器,那么设置器被调用。如果要绕过这些设置器,可以在选项中设置raw: true
选项。
当通过一对象进行设置时,它会是一个循环对象,会为其中的每个key/value
分别调用此方法。当设置raw
时,底层的dataValues
会被直接设置或扩展。
当值被修改后,修改值会被存储在的previous
中,并会设置一个changed
标识。
Set
同样可以用于构建关联实例。当设置时,应该确认属性键能够匹配到关系实例的别名,并确认这些选项已设置关联。
在JSON/JSONB属性中,如果使用.
分隔的字段,那么设置嵌套对象的值。
key
- {String | Object},表示要设置值的字段value
- {any},表示要设置的值[options]
- {Object}[options.raw=false]
- {Boolean},虚拟设置器会被忽略[options.reset=false]
- {Boolean},清除之前的设置数据
别名:setAttributes
2.9 changed()
- 判断是否修改
instance.changed([key]) -> Boolean|Array
判断字段或实例是否修改过,即判断dataValues
中的值是否与_previousDataValues
中的值是否相同。
当不传入参数时,会返回一个包含已修改字段的数组。当传入参数时,返回一个表示该字段是否修改的布尔值。
2.10 previous()
- 返回修改前的值
instance.previous([key]) -> any|Array.<any>
返回实例修改前的值,即_previousDataValues
属性中值。如果不传入参数,则返回所有已修改的值。
2.11 save()
- 保存实例到数据库
instance.save([options]) -> Promise.<this|Errors.ValidationError<
较验数据,通过后持久化到数据库中。这个方法仅会保存修改过的数据,如果未发生修改那么不会进行任何操作。
操作成功会回调修改结果,验证失败则返回一个Sequelize.ValidationError
对象。
[options]
- {Object}[options.fields]
- {Array.<string>},可选的表示数据库中字段值,提供后仅会验证和保存其中的字段[[options.silent=false]]
- {Boolean},设置为 true 时,updatedAt在更新时不会发生变化[options.validate=true]
- {Boolean},保存前时否验证[options.logging=false]
- {Function},一个用于打印执行SQL的函数[options.transaction=false]
- {Transaction}[options.searchPath=DEFAULT]
- {String},指定schema的 search_path (仅 Postgres)
2.12 reload()
- 重新加载数据
instance.reload([options]) -> Promise.<this>
用数据库中的数据当前实例。这不同于find(Instance.id)
,因为它会创建并返回一个新实例。而该方法是用新数据刷新当前实例。
[options]
- {Object}[options.logging=false]
- {Function},一个用于打印执行SQL的函数
2.13 validate()
- 验证属性
instance.validate([options]) -> Promise.<Errors.ValidationError|undefined>
根据模型定义的验证规则验证模型属性。验证成功时返回null
,否则返回一个错误对象。
[options]
- {Object}[options.skip]
- {String|Array},包含一个要跳过的验证字段的字符串或数组
2.14 update()
- 设置并保存
instance.update(updates, options) -> Promise.<this>
相当于调用set
方法后再调用save
,但它只保存传递给它确切值,使用它更新时更原子和更安全。
updates
- {Object},见set
options
- {Object},见save
别名:updateAttributes
2.15 destroy()
- 删除
instance.destroy([options={}]) -> Promise.<undefined>
删除实例在数据库中对应的行。设置为软删除(paranoid
)时,数据行并不会真实删除,而是将deletedAt
列更新为当前时间。
[options]
- {Object}[options.force=false]
- {Boolean},强制删除。设置为 true时,软删除的模型也会强制删除[options.logging=false]
- {Function},一个用于打印执行SQL的函数[options.transaction]
- {Transaction}[options.searchPath=DEFAULT]
- {String},指定schema的 search_path (仅 Postgres)
2.16 restore()
- 数据恢复
instance.restore([options={}]) -> Promise.<undefined>
恢复实例数据,仅适用于软删除(paranoid
)模型
[options]
- {Object}[options.logging=false]
- {Function},一个用于打印执行SQL的函数[options.transaction]
- {Transaction}
2.17 increment()
- 字段值增加
instance.increment(fields, [options]) -> Promise<this>
为一个或多个字段增加值。这一操作在数据库中完成,也就是说它并不使用实例的存储值。其增加值使用如下语句完成:
SET column = column + X
增加后,要获取正确的实例值应该使用reload()
方法重新加载数据。
fields
- {String | Array | Object},要增加值的字段[options]
- {Object}[options.by=1]
- {Integer},要增加的数字值[options.logging=false]
- {Function},一个用于打印执行SQL的函数[options.transaction]
- {Transaction}[options.searchPath=DEFAULT]
- {String},指定schema的 search_path (仅 Postgres)
instance.increment('number') // 增加 1 instance.increment(['number', 'count'], { by: 2 }) // 'number' 和 'count'两个字段增加 2 instance.increment({ answer: 42, tries: 1}, { by: 2 }) // 'answer'字段增加 42, 'tries' 字段增加 1,'by' 参数将忽略,因为每一列都有自己的值
2.18 decrement()
- 字段值减小
instance.decrement(fields, [options]) -> Promise<this>
为一个或多个字段减小值。这一操作在数据库中完成,也就是说它并不使用实例的存储值。其增加值使用如下语句完成:
SET column = column - X
增加后,要获取正确的实例值应该使用reload()
方法重新加载数据。
fields
- {String | Array | Object},要减小值的字段[options]
- {Object}[options.by=1]
- {Integer},要减小的数字值[options.logging=false]
- {Function},一个用于打印执行SQL的函数[options.transaction]
- {Transaction}[options.searchPath=DEFAULT]
- {String},指定schema的 search_path (仅 Postgres)
instance.decrement('number') // 减小 1 instance.decrement(['number', 'count'], { by: 2 }) // 'number' 和 'count'两个字段减小 2 instance.decrement({ answer: 42, tries: 1}, { by: 2 }) // 'answer'字段减小 42, 'tries' 字段减小 1, 'by' 参数将忽略,因为每一列都有自己的值
2.19 equals()
- 实例值是否相等
instance.equals(other) -> Boolean
检查当前实例是否与other
实例的值相等
2.20 equalsOneOf()
- 实例值其中的一个相等
instance.equalsOneOf(others) -> Boolean
检查当前实例是否与others
数组中的任意一个实例的值相等
2.21 toJSON()
- 转换成JSON
instance.toJSON() -> object
将当前实例转换为JSON形式,意味着会从数据库中取值,并应用所有自定义的访问器。