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

比如,当被关联的时候,大部分钩子将相同地工作,除了下面的部分:

  1. When using add/set functions the beforeUpdate/afterUpdate hooks will run.当使用beforeUpdate/afterUpdate钩子会运行的add/set函数时
  2. The only way to call beforeDestroy/afterDestroy hooks are on associations with onDelete: 'cascade' and the option hooks: 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的更多相关文章

  1. windows10安装nodejs 10和express 4

    最进做一个个人博客系统,前端用到了semanticUI,但是要使用npm工具包,所以需要安装nodejs,nodejs自带npm 下载 去官网下载自己系统对应的版本,我的是windows:下载 可以在 ...

  2. 基于Nodejs的sequelize操纵数据库

    ## 使用基于ORM架构的sequelize操纵数据库 ### 1.技术背景 ```Sequelize是一个基于promise的关系型数据库ORM框架,*********************技术文 ...

  3. 【前端】nodejs的ORM框架sequelize的工厂化

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/sequelize_factory.html 一.什么是sequelize nodejs的后台在操作数据库的时候,需 ...

  4. sequelize 学习之路

    如果你觉得Sequelize的文档有点多.杂,不方便看,可以看看这篇. 在使用NodeJS来关系型操作数据库时,为了方便,通常都会选择一个合适的ORM(Object Relationship Mode ...

  5. Sequelize 类 建立数据库连接 模型定义

    1:Sequelize 类 Sequelize是引用Sequelize模块获取的一个顶级对象,通过这个类可以获取模块内对其他对象的引用.比如utils.Transaction事务类.通过这个顶级对象创 ...

  6. Sequelize 和 MySQL 对照Sequelize 和 MySQL 对照

    安装 这篇文章主要使用MySQL.Sequelize.co来进行介绍.安装非常简单: $ npm install --save co $ npm install --save sequelize $ ...

  7. Sequelize 数据类型

    Sequelize.STRING // VARCHAR(255)Sequelize.STRING(1234) // VARCHAR(1234)Sequelize.STRING.BINARY // VA ...

  8. Sequelize模型定义

    定义 定义模型与表之间的映射,使用 define 方法. Sequelize 会自动增加 createdAt 和 updated 属性,这样能知道一个实例的创建时间和最终修改时间.如果不想自动生成,可 ...

  9. Linux下安装部署NodeJS完整步骤

    关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ NodeJS是一个开源,跨平台,轻量级的JavaScript运行时环境,可用于构建可扩展的网络 ...

随机推荐

  1. CSS关于文本渲染的属性text-rendering

    CSS关于文本渲染的属性text-rendering告诉渲染引擎工作时如何优化显示文本. 浏览器会在渲染速度.易读性(清晰度)和几何精度方面做一个权衡. 我们知道,SVG-可缩放矢量图形(Scalab ...

  2. CSS通过设置position定位的三种常用定位

    CSS中可以通过设置为元素设置一个position属性值,从而达到将不同的元素显示在不同的位置,或者固定显示在某一个位置,或者显示在某一层页面之上. position的值可以设为relative,ab ...

  3. IOS下 input 被软键盘方案遮盖问题解决

    前言: 并没有完美解决 ! 场景: 最近在做企业微信H5的一个项目,里面有个动态列表页,开始输入框是隐藏的,点击评论才会出现并让 input 聚焦.经过测试在安卓上面应该没什么问题,但是iOS上面会出 ...

  4. 利用:before和:after伪类制作类似微信对话框

    今天学到了怎么做一个小三角形,进而结合其他属性把类似微信对话框的图形做出来了. 先做出如下形状: .arrow { width: 30px; height:30px; border-width:20p ...

  5. javaSE——简单的文件浏览器

    import java.io.File; public class Demo02 { public static void main(String[]args){ File file = new Fi ...

  6. ubuntu中获取文件名称并生成txt文件

    简介: 在机器视觉学习过程中,通常会经常批量处理一些图片,在Ubuntu下可以使用find命令,来实现将文件名全部读取出来,生成列表txt文件,作为标签使用 (1)find命令格式如下: find / ...

  7. React-Native开发之原生模块封装(Android)升级版

     本文主题:如何实现原生代码的复用,即如何将原生模块封装. (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/52862 ...

  8. Android EditText方框验证码 短信验证码攻略

    本文由xiawe_i提供. xiawe_i的博客地址是: http://www.jianshu.com/u/fa9f03a240c6 项目中有这样一个需求: 验证码页是四个方框,输入验证码方框颜色改变 ...

  9. XSS学习(未完..)

    前言 XSS 漏洞原理非常简单,实际应用中非常灵活,于是通过 prompt(1) to win 来学习学习 正文 工具 分析正则表达式 https://regex101.com/ http://xss ...

  10. android 自定义控件之ViewGroup生命周期执行步骤

    前言 了解ViewGroup的生命周期的执行步骤对于自己自定义ViewGroup的时候十分重要,清楚了整个流程才能对ViewGroup有更深的理解.本文从个人的总结,来阐述一下执行的顺序.执行说明 首 ...