【Sequelize】关联模型和孤儿记录

news/2025/4/22 1:24:20

一、关联模型的核心机制

1. 关联类型与组合规则

基础四类型
hasOne:外键存储于目标模型(如用户档案表存储用户ID)
belongsTo:外键存储于源模型(如订单表存储用户ID)
hasMany:一对多关系,外键在目标模型(如用户有多篇文章)
belongsToMany:通过中间表实现多对多(如用户-角色中间表)

必须成对定义
• 单边定义会导致预加载失效。例如仅定义Foo.hasOne(Bar)时,无法通过Bar.findAll({ include: Foo })查询
• 正确组合方式:

 // 一对一User.hasOne(Profile);Profile.belongsTo(User);// 一对多User.hasMany(Post);Post.belongsTo(User);// 多对多User.belongsToMany(Role, { through: UserRole });Role.belongsToMany(User, { through: UserRole });

有关联字段的表,一定是属于 belongsTo 其他表的。

2. 高级关联配置

自定义外键与别名

User.hasMany(Comment, {foreignKey: 'authorId',  // 覆盖默认的userIdas: 'reviews'           // 通过user.getReviews()访问
});

当模型名称复数形式异常时(如Person→People),需通过as别名修正方法名

非主键关联

Ship.belongsTo(Captain, {targetKey: 'name',  // 关联船长表的name字段(需唯一约束)foreignKey: 'captainName'
});

需确保目标字段有唯一索引,否则会报错

3. 实际应用

在模型定义的时候关联模型:

在这里插入图片描述

然后再进行查询的第三个配置参数中定义 condition,来对查询结果进行关联:

在这里插入图片描述


二、孤儿记录的防护策略

孤儿记录:比如一个分类中关联了多个课程,此时将这个分类删掉,那么课程将找不到父记录,因此就成为了孤儿记录。

解决这个问题有三个方法:

  1. 设置外键约束(一般不用,在数据量大、高并发的场景下,会出现性能瓶颈)
  2. 删除分类的同时,删除该分类下的所有课程(代码层面,问题是可能发生误删除操作)
  3. 只有当没有关联该分类的课程时,才能被删掉(代码层面,推荐)
1. 外键约束级联

在定义关联时启用数据库级联删除,确保父记录删除时自动清理子记录:

// 用户删除时级联删除文章
User.hasMany(Post, {foreignKey: { allowNull: false }, // 强制外键非空onDelete: 'CASCADE' // 关键配置
});

此配置会在SQL层面生成ON DELETE CASCADE约束,彻底避免孤儿记录

2. 中间表清理(多对多关系)

使用钩子函数清理关联记录:

// 删除教师前清理关联表
Teacher.beforeDestroy(async (teacher) => {await Relation.destroy({where: { teacherId: teacher.id }});
});

特别适用于多对多关系中间表的数据维护

3. 事务保护

关键操作使用事务保证原子性:

await sequelize.transaction(async (t) => {const user = await User.findByPk(1, { transaction: t });await user.destroy({ transaction: t });// 自动触发关联的级联删除
});

防止在删除过程中断导致数据不一致


三、最佳实践建议

  1. 索引优化
    • 所有外键字段必须建立索引
    • 多对多中间表的联合索引:

    Relation.init({studentId: { type: INTEGER, primaryKey: true },teacherId: { type: INTEGER, primaryKey: true }
    }, { sequelize });
    

    通过复合主键提升查询效率

  2. 数据验证

    Post.belongsTo(User, {foreignKey: {validate: {isUserIdValid(value) {if (!validator.isUUID(value)) throw new Error('非法用户ID');}}}
    });
    
  3. 预加载优化

    User.findAll({include: [{model: Post,attributes: ['id', 'title'], // 按需加载字段where: { status: 'published' } // 过滤条件}]
    });
    

    避免N+1查询问题



https://dhexx.cn/news/show-5497382.html

相关文章

GPTNet如何革新创意与效率

引言 人工智能正在以前所未有的速度改变我们的工作与生活方式,从智能写作到视觉创作,AI工具已成为不可或缺的伙伴。在众多平台中,GPTNet以其强大的功能整合和直观体验崭露头角。它不仅汇集了GPT系列、Claude、Grok、Gemini等顶级对话模型&am…

Debian服务器挂载外部存储设备的完整指南

在 Debian 系统中挂载外部存储设备(如 U 盘、移动硬盘、SSD)是服务器运维和桌面使用中非常常见的操作。本文将为你详细拆解从识别设备、格式化到手动/自动挂载的全过程,适合新手到进阶用户参考。 一、准备阶段:插入存储设备并识别 1. 插入外部设备后查看…

ns-3中UDP饱和流发包时间间隔设置最合理值

ns3的官方手册很全,相关书籍也是有的,官网先贴在这里: ns-3 | a discrete-event network simulator for internet systemsa discrete-event network simulator for internet systemshttps://www.nsnam.org/相关的脚本介绍也都有一些&#xf…

V型调节阀:专为解决锂电池行业碳酸锂结晶介质的革命性方案-耀圣

V型调节阀:专为解决锂电池行业碳酸锂结晶介质的革命性方案 随着全球新能源汽车及储能产业的爆发式增长,锂电池核心材料碳酸锂的需求持续攀升。然而,碳酸锂生产过程中的结晶环节常面临介质堵塞、粒度不均、效率低下等难题,直接影…

删除win11电脑上的阿尔巴尼亚输入法SQI

删除电脑自带的阿尔巴尼亚输入法 这个输入法在系统中并不显示,但是有时候会出现在右下角显示,删除这个输入法的流程如下,暂时没发现反复! 第一步:打开注册表: winR打开运行,输入 regedit 第二…

THCON 2025

Crypto OTPas_ouf 用10个字符异或加密的jpg图片,通过头得到key再恢复原图 Mammoths Personnal Slot Machine 梅森旋转恢复 from pwn import * from randcrack import RandCrack from tqdm import trange context.log_level errorp remote(74.234.198.209, 33…

基于RV1126开发板的rknn-toolkit-lite使用方法

1. rknn-toolkit-lite介绍 rknn-toolkit-lite是用于python算法的推理的组件,当前已经在EASY-EAI-Nano完成适配,用户可以用它进行深度学习算法的纯python开发。而且同时支持已经进行了预编译的模型,短短几行代码即可完成算法的推理&#xff0c…

LeetCode面试热题150中12-18题学习笔记(用Java语言描述)

Day 03 12、 O ( 1 ) O(1) O(1)时间插入、删除元素和获取元素 需求:实现RandomizedSet 类: RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否…

【Linux】系统入门

【Linux】系统初识 起源开源 闭源版本内核内核编号 Linux的安装双系统(不推荐)WindowsLinuxvmware虚拟机vitualbox操作系统的镜像centos 7/ubuntu云服务器租用 Linux的操作lsmkdir 文件名pwdadduser userdel -rrm文件名cat /proc/cpuinfolinux支持编程vim code.c./a.out 运行程…

AOSP Android14 Launcher3——底部任务栏Taskbar详解

前言:Launcher3中底部Taskbar和Navbar,或者说中文里面的术语导航栏,这几个词是很容易让人混淆的地方。本文要介绍的是Taskbar。从字面上意思来看,Taskbar就是任务栏,任务栏是Launcher3中一个重要的组件,尤其…