当前位置: 首页 > 后端技术 > Node.js

Sequelize中文文档v4-Hooks-Hook

时间:2023-04-03 14:17:23 Node.js

Hooks-Hook本系列文章的应用实例已发布在GitHub上:sequelize-docs-Zh-CN。您可以Fork以帮助改进或Star以关注更新。欢迎使用Star.Hook(也称为生命周期事件)是在执行sequelize调用之前和之后调用的函数。例如,如果您希望始终在保存模型之前设置该值,您可以添加一个beforeUpdate挂钩。有关完整列表,请参阅Hooks文件。操作列表(1)beforeBulkCreate(instances,options)beforeBulkDestroy(options)beforeBulkUpdate(options)(2)beforeValidate(instance,options)(-)validate(3)afterValidate(instance,options)-or-validationFailed(instance,options),error)(4)beforeCreate(instance,options)beforeDestroy(instance,options)beforeUpdate(instance,options)beforeSave(instance,options)beforeUpsert(values,options)(-)创建销毁更新(5)afterCreate(instance,options))afterDestroy(instance,options)afterUpdate(instance,options)afterSave(instance,options)afterUpsert(created,options)(6)afterBulkCreate(instances,options)afterBulkDestroy(options)afterBulkUpdate(options)传递声明的HookHook的参数引用。这意味着您可以更改该值,它将反映在插入/更新语句中。挂钩可能包含异步操作——在这种情况下,挂钩函数应该返回一个承诺。目前有三种编程方式添加钩子的方法://方法1通过.define()方法constUser=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';}}});//方法2通过.hook()方法(或其别名.addHook()方法)User.hook('beforeValidate',(user,options)=>{user.mood='happy';});User.addHook('afterValidate','someCustomName',(user,options)=>{returnsequelize.Promise.reject(newError("恐怕我不能让你这样做!”)));});//方法3通过直接方法User.beforeCreate((user,options)=>{returnhashPassword(user.password).then(hashedPw=>{user.password=hashedPw;});});User.afterValidate('myHookAfter',(user,options)=>{user.username='Toni';});RemovingaHook只能删除带有name参数的hook。constBook=sequelize.define('book',{title:DataTypes.STRING});Book.addHook('afterCreate','notifyUsers',(book,options)=>{//...});Book.removeHook('afterCreate','notifyUsers');您可以有多个同名的钩子。调用.removeHook()将删除它们。Global/UniversalHook全局钩子是所有模型的钩子。它们可以定义您想要的所有模型行为,并且对插件特别有用。它们可以通过两种方式定义,语义略有不同:}}}});这将为所有模型添加一个默认挂钩,如果模型没有定义自己的beforeCreate挂钩,它将运行。constUser=sequelize.define('user');constProject=sequelize.define('project',{},{hooks:{beforeCreate:()=>{//做点别的事}}});User.create()//运行全局hookProject.create()//运行它自己的钩子(因为全局钩子被覆盖)Sequelize.addHook(常驻钩子)sequelize.addHook('beforeCreate',()=>{//做点什么});这个钩子总是在创建之前运行,不管模型是否指定了它自己的beforeCreate钩子:constUser=sequelize.define('user');constProject=sequelize.define('project',{},{hooks:{beforeCreate:()=>{//做点别的事}}});User.create()//runglobalhookProject.create()//在运行自己的hook之后运行globalhooklocalhooktotal在globalhook之前运行。ExampleHook当您编辑单个对象时,以下钩子将触发beforeValidateafterValidate或validationFailedbeforeCreate/beforeUpdate/beforeDestroyafterCreate/afterUpdate/afterDestroy//...Define...User.beforeCreate(user=>{if(user.accessLevel>10&&user.username!=="Boss"){thrownewError("Youcannotgrantthisuseraccesslevelsabovelevel10!")}})这个例子会返回一个错误:User.create({username:'NotaBoss',accessLevel:20}).catch(err=>{console.log(err);//您不能授予该用户高于10的访问级别!});以下示例将返回成功:User.create({username:'Boss',accessLevel:20}).then(user=>{console.log(user);//UserobjectwithusernameBossandaccessLevel20});ModelHook有时,您将通过使用模型上的bulkCreate、update、destroy方法一次编辑多条记录。当您使用以下方法之一时,将触发以下内容:beforeBulkCreate(instances,options)beforeBulkUpdate(options)beforeBulkDestroy(options)afterBulkCreate(instances,options)afterBulkUpdate(options)afterBulkDestroy(options)触发钩子,以及批量钩子,您可以将personalHooks:true传递给通话。Model.destroy({where:{accessLevel:0},individualHooks:true});//将选择所有要删除的记录并触发Model.update({username:'Toni'}before+aftereachinstancedelete,{where:{accessLevel:0},individualHooks:true});//所有要更新的记录都会在每次实例更新前+后被选中并触发Hook方法的options参数会提供给相应的方法或其clone和扩展版本的第二个参数。Model.beforeBulkCreate((records,{fields})=>{//records=发送到.bulkCreate的第一个参数//fields=发送到.bulkCreate的第二个参数之一})Model.bulkCreate([{username:'Toni'},//一些记录参数{username:'Tobi'}//一些记录参数],{fields:['username']}//optionparameters)Model.beforeBulkUpdate(({attributes,where})=>{//where-发送到.update的第二个参数的克隆字段之一//attributes-用于扩展的.update第二个参数的克隆字段之一})Model.update({gender:'Male'}/*属性参数*/,{where:{username:'Tom'}}/*where参数*/)Model.beforeBulkDestroy(({where,individualHooks})=>{//individualHooks-第二个参数被扩展克隆被发送到Model.destroy的默认值覆盖//其中-第二个参数是发送到Model.destroy的克隆的字段之一})Model.destroy({where:{username:'Tom'}}/*where参数*/)如果Model.bulkCreate(...)与updates.OnDuplicate参数一起使用,则在钩子中对updatesOnDuplicate数组中未给出的字段所做的更改将不会持久保存到数据库中。但是,如果这是您想要的,您可以更改挂钩中的updatesOnDuplicate选项。//使用updatesOnDuplicate选项批量更新现有用户((users,options)=>{for(constuserofusers){if(user.isMember){user.memberSince=newDate();}}//添加memberSince到updatesOnDuplicate否则memberSince日期将不会保存到数据库options.updatesOnDuplicate.push('memberSince');});关联在大多数情况下,关联实例的挂钩是相同的,除了少数情况。使用添加/设置功能时,将运行更新前/更新后挂钩。调用beforeDestroy/afterDestroy钩子的唯一方法是与onDelete:'cascade和参数hooks:true相关联。例如:constProjects=sequelize.define('projects',{title:DataTypes.STRING});constTasks=sequelize.define('tasks',{title:DataTypes.STRING});Projects.hasMany(Tasks,{onDelete:'cascade',hooks:true});Tasks.belongsTo(项目);此代码将在Tasks表上运行beforeDestroy/afterDestroy。默认情况下,Sequelize将尝试尽可能优化您的查询。当在删除时调用级联时,Sequelize将简单地执行DELETEFROM`table`WHEREassociatedIdentifier=associatedIdentifier.primaryKey但是,添加hooks:true将明确告诉Sequelize优化不是您关心的,并将在关联对象上执行ASELECT并一一删除每个实例,以便能够使用正确的参数调用挂钩。如果您的关联类型是n:m,您可能有兴趣在使用remove调用时触发直通模型上的挂钩。在内部,sequelize使用Model.destroy,导致在每个实例上调用bulkDestroy而不是before/afterDestroy挂钩。这可以很容易地通过将{individualHooks:true}传递给remove调用来修复,导致每个钩子通过实例对象被删除。事务注意事项请注意,Sequelize中的许多模型操作允许您在方法的选项参数中指定事务。如果在原始调用中指定了事务,它将出现在传递给挂钩函数的选项参数中。例如,请参考下面的代码片段://这里我们使用了异步钩子的promise风格,而不是回调。User.hook('afterCreate',(user,options)=>{//'transaction'将在options.transaction中可用//此操作将是与原始User.create调用相同的事务的一部分。返回User.update({mood:'sad'},{where:{id:user.id},transaction:options.transaction});});sequelize.transaction(transaction=>{User.create({username:'someguy',mood:'happy',transaction});});如果我们没有在上面代码中的User.update调用中包含事务选项,则不会发生任何更改,因为在提交未决事务之前,我们新创建的用户不存在于数据库中。内部事务认识到sequelize可能在内部使用事务来进行某些操作(如Model.findOrCreate)是非常重要的。如果你的钩子函数执行依赖于对象在数据库中的存在的读取或写入操作,或者修改对象的存储值,如上一节中的示例,你应该始终指定{transaction:options.transaction}。如果在处理操作的过程中已经调用了挂钩,这将确保您的相关读/写是同一事务的一部分。如果钩子没有被处理,你只需要指定{transaction:null}并且可以期待默认行为。如果本文对您有帮助,请在下方点赞或starGitHub:sequelize-docs-Zh-CN支持,谢谢。