当前位置: 首页 > news >正文

Thinkphp的belongsToMany(多对多) 和 hasManyThrough(远程一对多)的区别是什么?

虽然 belongsToMany(多对多) 和 hasManyThrough(远程一对多) 都会使用 JOIN 查询,但它们的核心区别在于 关联关系的本质不同,具体如下:


1️⃣ belongsToMany(多对多)

📌 适用场景

两个表之间是多对多关系,并且需要通过中间表来关联数据。例如:

  • 用户 users角色 roles 之间是多对多关系。
  • 中间表 access 记录用户与角色的对应关系。

🛠 数据库结构

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE roles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    role_name VARCHAR(255) NOT NULL
);

CREATE TABLE access (
    user_id INT NOT NULL,
    role_id INT NOT NULL,
    PRIMARY KEY (user_id, role_id),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);

🔎 ThinkPHP 代码

class User extends Model 
{
    public function roles()
    {
        return $this->belongsToMany(Role::class, 'access');
    }
}

查询 用户 ID=1 的所有角色:

$user = User::find(1);
$roles = $user->roles;

最终生成的 SQL:

SELECT r.*
FROM roles r
JOIN access a ON r.id = a.role_id
WHERE a.user_id = 1;

特点

  • 需要中间表(access 存储关系。
  • 查询时通过 JOIN 中间表,找到对应的多个角色(多对多)。
  • 数据模型: 一个用户有多个角色,一个角色也可能属于多个用户。

2️⃣ hasManyThrough(远程一对多)

📌 适用场景

两个表之间没有直接关联,但可以通过中间表建立关系,例如:

  • 每个城市(cities)有多个用户(users
  • 每个用户(users)有多个话题(topics
  • citiestopics 之间没有直接的关系(需要通过 users 进行关联)

🛠 数据库结构

CREATE TABLE cities (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    city_id INT NOT NULL,
    FOREIGN KEY (city_id) REFERENCES cities(id) ON DELETE CASCADE
);

CREATE TABLE topics (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255) NOT NULL,
    user_id INT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

🔎 ThinkPHP 代码

class City extends Model 
{
    public function topics()
    {
        return $this->hasManyThrough(Topic::class, User::class);
    }
}

查询 城市 ID=1 的所有话题:

$city = City::find(1);
$topics = $city->topics;

最终生成的 SQL:

SELECT t.*
FROM topics t
JOIN users u ON t.user_id = u.id
WHERE u.city_id = 1;

特点

  • 没有中间表(不像 belongsToMany)。
  • 需要通过 另一张表(users 进行跨表关联查询
  • 数据模型: 一个城市有多个话题,但城市表和话题表之间无直接关系,只能通过 users 关联。

🔎 主要区别总结

关联方式适用场景需要中间表?关联方式MySQL 查询关联模型关系类型
belongsToMany(多对多)用户 - 角色✅ 需要(accessJOIN 中间表JOIN accessUser -> roles()多对多
hasManyThrough(远程一对多)城市 - 话题❌ 不需要通过另一张表远程关联JOIN usersCity -> topics()远程一对多

🛠 用类比解释

belongsToMany(多对多)

像是 学生(User)和课程(Role) 之间的关系:

  • 一个学生可以选多门课
  • 一门课可以有多个学生
  • 但学生和课程 不是直接关联的,而是通过 选课表(access) 连接的。

hasManyThrough(远程一对多)

像是 学校(City)和课表(Topic) 之间的关系:

  • 每个 学校 有多个 学生
  • 每个 学生 有多个 课表
  • 学校和课表 之间没有直接关系,只能通过 学生表 关联。

✅ 结论

虽然 belongsToManyhasManyThrough 都使用 JOIN 查询,但:

  1. belongsToMany 是多对多关系,必须有中间表access)。
  2. hasManyThrough 远程一对多,不需要中间表,但需要一个中间关联模型(如 users)。
  3. SQL 查询方式不同
    • belongsToMany 直接 JOIN 中间表
    • hasManyThrough 远程查询,JOIN 另一张表

相关文章:

  • 【蓝桥杯】省赛:连连看(暴力 非AC)
  • 浅析Redis分布式锁的实现方法
  • 使用OpenAI Python库探索新一代AI接口:从基础到智能体开发
  • 文本组件+Image组件+图集
  • 数学复习(8)连续性
  • STM32F407ZGT6--工程模版
  • 10.2linux内核定时器实验(详细编程)_csdn
  • Windows环境下安装部署dzzoffice+onlyoffice的私有网盘和在线协同系统
  • 【USTC 计算机网络】第一章:计算机网络概述 - Internet、网络边缘、网络核心、接入网与物理媒体
  • 基于变分推理与 Best‑of‑N 策略的元 Prompt 自动生成与优化框架
  • 学习路之TP6 --重写vendor目录下的文件(服务覆盖command---优点:命令前后一致)
  • 在线 SQL 转 SQLAlchemy:一键生成 Python 数据模型
  • 谷歌Gemini 3大模型发布,AI领域再掀波澜!(2)
  • 如何通过 Airbyte 将数据摄取到 Elasticsearch
  • 【Linux我做主】基础命令完全指南上篇
  • 如何在 VS编译器上使用 C99规定的变长数组------使用Clang工具
  • 如何用URDF文件构建机械手模型并与MoveIt集成
  • LeetCode 解题思路 17(Hot 100)
  • 【GB28181】H265-Nalu的封装
  • 让双向链表不在云里雾里
  • 知名中医讲师邵学军逝世,终年51岁
  • 新疆多地市民拍到不明飞行物:几秒内加速消失,气象部门回应
  • 国宝文物子弹库帛书二、三卷从美启程,18日凌晨抵京
  • 蒲慕明院士:未来数十年不是AI取代人,而是会用AI的人取代不会用的
  • 湖南4个县市区被确定为野生蘑菇中毒高风险区:中毒尚无特效解毒药
  • 著名心血管病学专家李国庆教授逝世,享年63岁