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. Spring中的Bean的配置形式

    Spring中Bean的配置形式有两种,基于XML文件的方式和基于注解的方式. 1.基于XML文件的方式配置Bean <?xml version="1.0" encoding ...

  2. JAVA非静态成员变量之死循环

    1.非静态成员变量 当成员变量为非静态成员变量且对当前类进行实例化时,将会产生死循环 例子: public class ConstructorCls { private ConstructorCls ...

  3. Spring MVC入门(一)—— SpringMVC的执行流程与常用注解

    一.什么是SpringMVC SpringMVC就是类似于Struts2的mvc框架,属于SpringFrameWork的后续产品.在模型层中与视图层的交互部分. springMVC执行流程: 二.常 ...

  4. 适配器(GOF23)

    ---恢复内容开始--- 摘要:由于应用环境的变化,需要将现存的对象放到新的环境中去,但新环境的接口是现存对象不满足的. 意图:将原本接口不兼容的类通过转换,使得它们能够一起工作,复用现有的类 ada ...

  5. Bash:常用命令工具-tr命令

    tr命令可以用来做简单的字符替换与删除,常用的有-d, -s选项.它的替换与删除是按单个字符来的 假设有以下文本: Read from the file words.txt and output th ...

  6. STL:vector<bool> 和bitset

    今天某个地方要用到很多位标记于是想着可以用下bitset,不过发现居然是编译时确定空间的,不能动态分配.那就只能用vector来代替一下了,不过发现居然有vector<bool>这个特化模 ...

  7. js面向对象设计之class中一些坑和技巧

    this的指向 super 类工厂,类中定义方法名时,可以使用字符串,这就可以创建工厂函数(类似模板类) Generator 函数 静态属性和私有属性.私有方法 new.target

  8. excel导入 服务器忘了装组件了。。。

    excel导入 本地没问题 一直在找权限问题  最后发现服务器忘了装组件了... 郁闷 记录下 http://www.microsoft.com/zh-cn/download/confirmation ...

  9. SSL Certificates深入理解

    http://www.littlewhitedog.com/content-71.html https://www.verisign.com/en_US/website-presence/websit ...

  10. python之mechanize模拟浏览器

    安装 Windows: pip install mechanize Linux:pip install python-mechanize 个人感觉mechanize也只适用于静态网页的抓取,如果是异步 ...