Thinkphp的belongsToMany多对多-和-hasManyThrough远程一对多的区别是什么
目录
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
) - 但
cities
和topics
之间没有直接的关系 (需要通过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 (多对多) | 用户 - 角色 | ✅ 需要( access ) | JOIN 中间表 | JOIN access | User -> roles() | 多对多 |
hasManyThrough (远程一对多) | 城市 - 话题 | ❌ 不需要 | 通过 另一张表 远程关联 | JOIN users | City -> topics() | 远程一对多 |
🛠 用类比解释
belongsToMany
(多对多)
像是 学生(User)和课程(Role) 之间的关系:
- 一个学生可以选多门课
- 一门课可以有多个学生
- 但学生和课程 不是直接关联的 ,而是通过 选课表(access) 连接的。
hasManyThrough
(远程一对多)
像是 学校(City)和课表(Topic) 之间的关系:
- 每个 学校 有多个 学生
- 每个 学生 有多个 课表
- 但 学校和课表 之间 没有直接关系 ,只能通过 学生表 关联。
✅ 结论
虽然
belongsToMany
和
hasManyThrough
都使用
JOIN
查询
,但:
belongsToMany
是多对多关系,必须有中间表 (access
)。hasManyThrough
远程一对多,不需要中间表,但需要一个中间关联模型 (如users
)。- SQL 查询方式不同
:
belongsToMany
直接JOIN
中间表 。hasManyThrough
远程查询,JOIN
另一张表 。