Sequelize-nodejs-10-Hooks
Hooks钩子
Hooks (also known as lifecycle events), are functions which are called before and after calls in sequelize are executed. For example, if you want to always set a value on a model before saving it, you can add a beforeUpdate hook.
钩子(以生命周期事件闻名)是在sequelize的调用被执行的前后被调用的函数。比如,如果你总想要在模型中的值被保存前设置它,你可以添加beforeUpdate钩子
For a full list of hooks, see Hooks file.
Order of Operations操作顺序
()
beforeBulkCreate(instances, options)
beforeBulkDestroy(options)
beforeBulkUpdate(options)
()
beforeValidate(instance, options)
(-)
validate
()
afterValidate(instance, options)
- or -
validationFailed(instance, options, error)
()
beforeCreate(instance, options)
beforeDestroy(instance, options)
beforeUpdate(instance, options)
beforeSave(instance, options)
beforeUpsert(values, options)
(-)
create
destroy
update
()
afterCreate(instance, options)
afterDestroy(instance, options)
afterUpdate(instance, options)
afterSave(instance, options)
afterUpsert(created, options)
()
afterBulkCreate(instances, options)
afterBulkDestroy(options)
afterBulkUpdate(options)
Declaring Hooks声明
Arguments to hooks are passed by reference. This means, that you can change the values, and this will be reflected in the insert / update statement. A hook may contain async actions - in this case the hook function should return a promise.
钩子的变量将通过引用传递。这意味着以可以改变其值,这将会在insert / update语句中被影响。一个钩子可能包含异步行为-在这种情况下,钩子函数应该返回promise。
There are currently three ways to programmatically add hooks:
三种添加钩子的方法:
// Method 1 via the .define() method
const User = sequelize.define('user', {
username: DataTypes.STRING,
mood: {
type: DataTypes.ENUM,
values: ['happy', 'sad', 'neutral']
}
}, {
hooks: {
beforeValidate: (user, options) => {
user.mood = 'happy';
},
afterValidate: (user, options) => {
user.username = 'Toni';
}
}
}); // Method 2 via the .hook() method (or its alias .addHook() method)
User.hook('beforeValidate', (user, options) => {
user.mood = 'happy';
}); User.addHook('afterValidate', 'someCustomName', (user, options) => {
return sequelize.Promise.reject(new Error("I'm afraid I can't let you do that!"));
}); // Method 3 via the direct method
User.beforeCreate((user, options) => {
return hashPassword(user.password).then(hashedPw => {
user.password = hashedPw;
});
}); User.afterValidate('myHookAfter', (user, options) => {
user.username = 'Toni';
});
Removing hooks移除
Only a hook with name param can be removed.
只有带有名字变量的钩子能够被删除
const Book = sequelize.define('book', {
title: DataTypes.STRING
});
Book.addHook('afterCreate', 'notifyUsers', (book, options) => {
// ...
});
Book.removeHook('afterCreate', 'notifyUsers');
You can have many hooks with same name. Calling .removeHook() will remove all of them.
你可能会有很多有着相同名字的钩子。调用.removeHook()将会删除所有钩子
Global / universal hooks全局/通用钩子
Global hooks are hooks which are run for all models. They can define behaviours that you want for all your models, and are especially useful for plugins. They can be defined in two ways, which have slightly different semantics:
全局钩子是可以在所有模型中运行的。他们能够定义你想要在所有模型中实现的行为,对插件尤其有效。他们可以以两种方式定义,在语义上有所不同。
Sequelize.options.define (default hook)
const sequelize = new Sequelize(..., {
define: {
hooks: {
beforeCreate: () => {
// Do stuff
}
}
}
});
This adds a default hook to all models, which is run if the model does not define its own beforeCreate hook:
这添加了一个缺省钩子给所有模型,如果模型没有定义它自己的beforeCreate钩子时,这个缺省钩子就会运行
const User = sequelize.define('user');//没有定义自己的beforeCreate钩子,所以会调用缺省(全局)钩子
const Project = sequelize.define('project', {}, {//定义了自己的beforeCreate钩子
hooks: {
beforeCreate: () => {
// Do other stuff
}
}
});
User.create() // Runs the global hook
Project.create() // Runs its own hook (because the global hook is overwritten)
Sequelize.addHook (permanent hook)
sequelize.addHook('beforeCreate', () => {
// Do stuff
});
This hooks is always run before create, regardless of whether the model specifies its own beforeCreate hook:
这个钩子将会在创建前运行,不管一个模型是否定义了它自己的 beforeCreate钩子
const User = sequelize.define('user');
const Project = sequelize.define('project', {}, {
hooks: {
beforeCreate: () => {
// Do other stuff
}
}
});
User.create() // Runs the global hook
Project.create() // Runs its own hook, followed by the global hook,即先运行自己定义的,再运行global的钩子
Local hooks are always run before global hooks.
本地钩子将总是运行在全局钩子的前面
Instance hooks实例钩子
The following hooks will emit whenever you're editing a single object
无论你何时去编辑一个对象,下面的钩子将发行:
beforeValidate
afterValidate or validationFailed
beforeCreate / beforeUpdate / beforeDestroy
afterCreate / afterUpdate / afterDestroy // ...define ...需要自己定义
User.beforeCreate(user => {
if (user.accessLevel > && user.username !== "Boss") {
throw new Error("You can't grant this user an access level above 10!")
}
})
This example will return an error:
下面的例子将返回错误:(即将在create之前运行beforeCreate钩子)
User.create({username: 'Not a Boss', accessLevel: }).catch(err => {
console.log(err); // You can't grant this user an access level above 10!
});
The following example would return successful:
下面的例子将成功:
User.create({username: 'Boss', accessLevel: }).then(user => {
console.log(user); // user object with username as Boss and accessLevel of 20
});
Model hooks模型钩子
Sometimes you'll be editing more than one record at a time by utilizing the bulkCreate, update, destroy methods on the model. The following will emit whenever you're using one of those methods:
有时,你将通过使用模型中的bulkCreate, update, destroy方法去一次编辑多个记录。无论何时你使用这些方法之一的方法时,下面的钩子将会发行
beforeBulkCreate(instances, options)
beforeBulkUpdate(options)
beforeBulkDestroy(options)
afterBulkCreate(instances, options)
afterBulkUpdate(options)
afterBulkDestroy(options)
If you want to emit hooks for each individual record, along with the bulk hooks you can pass individualHooks: true to the call.
如果你想要为每个记录发行钩子的话,你可以传递individualHooks: true到bulk钩子中去调用:
Model.destroy({ where: {accessLevel: }, individualHooks: true});
// Will select all records that are about to be deleted and emit before- + after- Destroy on each instance
Model.update({username: 'Toni'}, { where: {accessLevel: }, individualHooks: true});
// Will select all records that are about to be updated and emit before- + after- Update on each instance
The options argument of hook method would be the second argument provided to the corresponding method or its cloned and extended version.
钩子方法的options变量将会成为提供给相关方法或其克隆和扩展版本的第二个变量:
Model.beforeBulkCreate((records, {fields}) => {
// records = the first argument sent to .bulkCreate
// fields = one of the second argument fields sent to .bulkCreate
})
Model.bulkCreate([
{username: 'Toni'}, // part of records argument
{username: 'Tobi'} // part of records argument
], {fields: ['username']} // options parameter
)
Model.beforeBulkUpdate(({attributes, where}) => {
// where - in one of the fields of the clone of second argument sent to .update
// attributes - is one of the fields that the clone of second argument of .update would be extended with
})
Model.update({gender: 'Male'} /*attributes argument*/, { where: {username: 'Tom'}} /*where argument*/)
Model.beforeBulkDestroy(({where, individualHooks}) => {
// individualHooks - default of overridden value of extended clone of second argument sent to Model.destroy
// where - in one of the fields of the clone of second argument sent to Model.destroy
})
Model.destroy({ where: {username: 'Tom'}} /*where argument*/)
If you use Model.bulkCreate(...) with the updatesOnDuplicate option, changes made in the hook to fields that aren't given in the updatesOnDuplicate array will not be persisted to the database. However it is possible to change the updatesOnDuplicate option inside the hook if this is what you want.
如果使用带有updatesOnDuplicate选项的Model.bulkCreate(...),在钩子中没有传给updatesOnDuplicate数组的对fields的更改将不会在数据库中保持数据的一致性。可是在钩子中改变updatesOnDuplicate选项是可能的,只要你想。
// Bulk updating existing users with updatesOnDuplicate option
Users.bulkCreate([
{ id: , isMember: true },
{ id: , isMember: false }
], {
updatesOnDuplicate: ['isMember']
}); User.beforeBulkCreate((users, options) => {
for (const user of users) {
if (user.isMember) {
user.memberSince = new Date();//这里将更改的数据是user中的memberSince,但是它没有在updatesOnDuplicate数组中,所以下面要将其添加进来
}
} // Add memberSince to updatesOnDuplicate otherwise the memberSince date wont be
// saved to the database
options.updatesOnDuplicate.push('memberSince');
});
Associations
For the most part hooks will work the same for instances when being associated except a few things
比如,当被关联的时候,大部分钩子将相同地工作,除了下面的部分:
- When using add/set functions the beforeUpdate/afterUpdate hooks will run.当使用beforeUpdate/afterUpdate钩子会运行的add/set函数时
- The only way to call beforeDestroy/afterDestroy hooks are on associations with
onDelete: 'cascade'and the optionhooks: true. For instance:唯一调用beforeUpdate/afterUpdate钩子的方法是与onDelete: 'cascade'和选项hooks: true关联
const Projects = sequelize.define('projects', {
title: DataTypes.STRING
});
const Tasks = sequelize.define('tasks', {
title: DataTypes.STRING
});
Projects.hasMany(Tasks, { onDelete: 'cascade', hooks: true });
Tasks.belongsTo(Projects);
This code will run beforeDestroy/afterDestroy on the Tasks table. Sequelize, by default, will try to optimize your queries as much as possible. When calling cascade on delete, Sequelize will simply execute a
这个代码将在Tasks表中运行beforeDestroy/afterDestroy。默认Sequelize将尽可能地试着优化你的查询。当在删除时调用cascade时,Sequelize将简单地执行:
DELETE FROM `table` WHERE associatedIdentifier = associatedIdentifier.primaryKey
However, adding hooks: true explicitly tells Sequelize that optimization is not of your concern and will perform a SELECT on the associated objects and destroy each instance one by one in order to be able to call the hooks with the right parameters.
可是,显式地添加hooks: true将告诉Sequelize优化器与你所想的不同,它将在关联对象中表现为SELECT和为了能够调用带有正确变量的钩子一个个破坏每个实例。
If your association is of type n:m, you may be interested in firing hooks on the through model when using the remove call. Internally, sequelize is using Model.destroy resulting in calling the bulkDestroy instead of the before/afterDestroy hooks on each through instance.
当你使用remove调用时,如果你的关联是类型n:m,你可能将会对在through模型中烧了钩子感兴趣。在内部,sequelize使用Model.destroy导致在每一个through实例中调用bulkDestroy而不是before/afterDestroy钩子
This can be simply solved by passing {individualHooks: true} to the remove call, resulting on each hook to be called on each removed through instance object.
这能够简单地通过传递{individualHooks: true}给remove调用来解决,这将导致在每个移除的through实例对象中的每个钩子被调用
A Note About Transactions
Note that many model operations in Sequelize allow you to specify a transaction in the options parameter of the method. If a transaction is specified in the original call, it will be present in the options parameter passed to the hook function. For example, consider the following snippet:
记住很多在Sequelize中的模型操作允许你在方法的options变量中指定事务。如果事务在初始调用中被指定,它将在传递给钩子函数的options变量中出现。比如下面的小片段:
// Here we use the promise-style of async hooks rather than
// the callback.
User.hook('afterCreate', (user, options) => {
// 'transaction' will be available in options.transaction // This operation will be part of the same transaction as the
// original User.create call.
return User.update({
mood: 'sad'
}, {
where: {
id: user.id
},
transaction: options.transaction
});
}); sequelize.transaction(transaction => {
User.create({
username: 'someguy',
mood: 'happy',
transaction
});
});
If we had not included the transaction option in our call to User.update in the preceding code, no change would have occurred, since our newly created user does not exist in the database until the pending transaction has been committed.
在之前的代码中,如果你对User.update的调用中没有包含事务选项,将不会发生任何变化,因此我们新的创建用户将不会在数据库中出现,知道正在运行中的食物被提交
Internal Transactions内部事务
It is very important to recognize that sequelize may make use of transactions internally for certain operations such as Model.findOrCreate. If your hook functions execute read or write operations that rely on the object's presence in the database, or modify the object's stored values like the example in the preceding section, you should always specify { transaction: options.transaction }.
意识到sequelize内部可能会为某些操作,比如Model.findOrCreate使用事务是十分重要的。如果你的钩子函数依据数据库中出现的对象执行读或写操作,或就像在前面部分的例子中修改对象的存储值,你应该总是指定{ transaction: options.transaction }
If the hook has been called in the process of a transacted operation, this makes sure that your dependent read/write is a part of that same transaction. If the hook is not transacted, you have simply specified { transaction: null } and can expect the default behaviour.
如果在事务操作的过程中调用了钩子,要保证你依赖的read/write操作是同一事务的一部分。如果钩子不是事务性的,你可以简单指明{ transaction: null }并期待缺省行为
Sequelize-nodejs-10-Hooks的更多相关文章
- windows10安装nodejs 10和express 4
最进做一个个人博客系统,前端用到了semanticUI,但是要使用npm工具包,所以需要安装nodejs,nodejs自带npm 下载 去官网下载自己系统对应的版本,我的是windows:下载 可以在 ...
- 基于Nodejs的sequelize操纵数据库
## 使用基于ORM架构的sequelize操纵数据库 ### 1.技术背景 ```Sequelize是一个基于promise的关系型数据库ORM框架,*********************技术文 ...
- 【前端】nodejs的ORM框架sequelize的工厂化
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/sequelize_factory.html 一.什么是sequelize nodejs的后台在操作数据库的时候,需 ...
- sequelize 学习之路
如果你觉得Sequelize的文档有点多.杂,不方便看,可以看看这篇. 在使用NodeJS来关系型操作数据库时,为了方便,通常都会选择一个合适的ORM(Object Relationship Mode ...
- Sequelize 类 建立数据库连接 模型定义
1:Sequelize 类 Sequelize是引用Sequelize模块获取的一个顶级对象,通过这个类可以获取模块内对其他对象的引用.比如utils.Transaction事务类.通过这个顶级对象创 ...
- Sequelize 和 MySQL 对照Sequelize 和 MySQL 对照
安装 这篇文章主要使用MySQL.Sequelize.co来进行介绍.安装非常简单: $ npm install --save co $ npm install --save sequelize $ ...
- Sequelize 数据类型
Sequelize.STRING // VARCHAR(255)Sequelize.STRING(1234) // VARCHAR(1234)Sequelize.STRING.BINARY // VA ...
- Sequelize模型定义
定义 定义模型与表之间的映射,使用 define 方法. Sequelize 会自动增加 createdAt 和 updated 属性,这样能知道一个实例的创建时间和最终修改时间.如果不想自动生成,可 ...
- Linux下安装部署NodeJS完整步骤
关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ NodeJS是一个开源,跨平台,轻量级的JavaScript运行时环境,可用于构建可扩展的网络 ...
随机推荐
- 如何灵活利用免费开源图标字体-IcoMoon篇——张鑫旭
一.温故知新 之前有专门介绍过如何使用类似fontforge软件制作自定义字符字体以及如何在web中实际应用. 不过,文中提到的是利用系统自带的一些特殊字体,如WINGDNG3.ttf字体. 显然,系 ...
- springMVC 简单应用
一,controller FileController package com.dkt.controller; import java.io.File; import java.io.FileInpu ...
- 慕课网 Ajax笔记
Ajax技术实现: 运用HTML和CSS来实现页面,表达信息: 运用XMLHttpRequest和web服务器进行数据的异步交换: 运用JavaScript操作DOM,实现动态局部刷新: 同步:就是用 ...
- owin Claims-based认证登录实现
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext c ...
- IIS测试环境搭建
1.控制面板->程序->程序和功能->打开或关闭Windows功能->Internet信息服务->Web管理工具,打开如下服务: 2.打开IIS管理器 2.1检查.net ...
- CSS 小结笔记之浮动
在css中float是一个非常好用的属性,float最基本用法是用来做文字环绕型的样式的. 基本用法:float:left | right 例如 <!DOCTYPE html> <h ...
- Java简单方法批量修改Windows文件夹下的文件名(简单IO使用)
package test.tttt; import java.io.File; import java.util.ArrayList; import java.util.List; public cl ...
- 《SQL Server 2008从入门到精通》--20180628
数据库基本概念:区.页.行 区:SQL Server中管理空间的基本单位.一个区大小为64KB,是八个物理上连续的页.SQL Server中每MB有16个区.一旦一个区被存储满,SQL Server将 ...
- 关于Vue中:key="index"的console警告
在写vue项目时,浏览器的console出现如下警告信息: [Vue warn]: Property or method "index" is not defined on the ...
- MySQL:关于 unauthenticated user
一.现象 在生产环境中我们偶尔会遇到show processlist:显示host为 unauthenticated user 这样的连接,同时伴有数据库服务器层面的load,sys cpu较高,或者 ...