一、一对一关系
1.获取用户详细信息
(1)不使用关联关系模型
在不使用关联关系模型时, 如果想获取用户的详细信息怎么处理?
需求: 查找xiaoming的手机号
分为两步
- 根据name查找user表, 找id
- 根据id查找user_info表, 条件是user_info表中的user_id=id
测试:
需要执行两条SQL语句, 最终返回的是一条user_info表中的数据
(2)获取用户详细信息使用关联关系模型
1) 在user模型中编写userInfo方法
在userInfo方法中, 调用hasOne(), 带3个参数
https://www.kancloud.cn/manual/thinkphp5_1/354057
// userInfo名字随便写小驼峰命名
public function userInfo()
{
/**
* 第一个参数: 要关联的模型类名
* 第二个参数: 外键名, 要关联的表中的字段
* 第三个参数: 主键名, 本表中跟关联表对应的字段
*/
return $this->hasOne('UserInfo', 'user_id', 'id');
}
2) 在控制器中调用
在控制器中调用时, user_info可以做为user模型的一个属性
来查询
关联方法命名是驼峰法,userInfo, 关联属性则是小写+下划线user_info
https://www.kancloud.cn/manual/thinkphp5_1/354057
// 使用关联模型,tp中数组可以当对象使用,对象当数组使用,tp做了转换
public function one_one_yes()
{
// 找到id为1的记录
$user = User::find(1);
dump($user);
// 会根据$user的id找UserInfo的user_id
dump($user->user_info);
}
3) 测试
2 根据关联表查本表
需求, 查询手机号为18973245670的用户密码
分析: 手机号保存在关联表user_info中, 密码在本表user中
一般的思路是:
- 先从user_info表中查找, 条件是tel=18973245670, 找到user_id(3)
- 再根据user_id到user表中查找, 条件是id=user_id(3)
1) 不使用关联关系
public function info2user()
{
//不使用关联关系
$tel = '18973245670';
// 查找user_id
$user_id = UserInfo::where('tel', $tel)->value('user_id');
// 通过id找用户,得到密码
$user = User::find($user_id);
echo $user->password;
}
也可以使用一条sql语句, 连表查询
select it_user.password from
it_user join it_user_info
on it_user_info.user_id =it_user.id
where it_user_info.tel='18973245670';
2) 使用关联关系
public function info2user()
{
// 使用关联关系
$tel = '18973245670';
// 第一个参数是关联方法名(不是关联模型名)
$user = User::hasWhere('userInfo', ['tel'=>$tel])->find();
echo $user->password;
}
说明:
执行的sql语句:
3 关联自动写入
分别创建两个模型, 在写入数据库时, 使用together
1) 关联新增
应用场景, 在添加用户的同时, 添加用户的详情
案例:
public function add()
{
$user = new User;
$user->name = 'xiaozhang';
$user->password = '123456';
$user_info = new UserInfo;
$user_info->tel = '13909876543';
$user_info->email = 'xiaozhang@163.com';
$user_info->addr = '南京';
// 建立关联关系
$user->user_info = $user_info;
// 这里必须指定关联属性名, user_info跟上面的关联属性保持一致
$user->together('user_info')->save();
}
测试
2) 关联更新
需求, 更新id为7的用户的密码和手机号
密码是保存在本表user中
手机号是保存在关联表user_info中
使用关联更新, 同时更新两张表
public function upd()
{
$user = User::find(7);
$user->password = '777';
$user->user_info->tel = '77777777';
$user->together('user_info')->save();
}
执行的sql语句
3) 关联删除
需求: 删除id为8的用户时, 同时删除详情
public function del()
{
$user = User::get(8, 'userInfo');
$user->together('user_info')->delete();
}
这个地方, tp好像有bug, 完全按照手册的写法写, 但是依然出问题
二、 一对多关系
用户表(it_user)和文章表(it_article)之间就是一对多关系
2.1 建立关联关系
在user模型中, 定义一个方法articles
public function articles()
{
/**
* 第一个参数: 要关联的模型名
* 第二个参数: 外键名, 要关联的表中的字段
* 第三个参数: 主键名, 本表中跟关联表对应的字段
*/
return $this->hasMany('Article', 'user_id', 'id');
}
2.2 关联查询
public function article()
{
$user = User::find(1);
// 将模型中的方法做为属性来使用
dump($user->articles);
}
效果
2.3 关联新增
public function article_add()
{
$data = [
'title'=>'新增的文章',
'content'=>'新增的文章'
];
$user = User::find(1);
// 这里的articles必须加(), 表示调用模型的方法
// 用户id1在article表也会插入用户关联id
$user->articles()->save($data);
}
执行的sql语句
2.4 关联删除
public function article_del()
{
// user id为1删除,article中关联记录也全部删除。要用get
$user = User::get(1, 'articles');
$user->together('articles')->delete();
}
执行的sql语句
三、 多对一关系
一对多关系反过来就是多对一关系
用户表(it_user)与国家表(it_country)之间就是多对一关系
3.1 建立关联关系
在用户模型(user)中, 定义一个方法country
public function country()
{
/**
* 第一个参数: 要关联的模型类名
* 第二个参数: 外键名, 由于本表是子表, 外键字段在本表中
* 第三个参数: 主键名, 需要关联的模型的主键
*/
return $this->belongsTo('Country', 'country_id', 'id');
}
3.2 关联查询
public function country()
{
$user = User::find(1);
dump($user->country);
}
四、 多对多关系
用户表(it_user)与角色表(it_role)是多对多的关系
对于多对多关系, 需要一张中间表(it_user_role)
4.1 建立关联关系
在User模型中, 定义一个roles方法
public function roles()
{
/**
* 第一个参数: 要关联的模型类名
* 第二个参数: 中间表名
* 第三个参数: 外键, 中间表的当前模型外键
* 第四个参数: 关联键, 中间表的当前模型关联键名
*/
return $this->belongsToMany('Role', 'user_role', 'role_id', 'user_id');
}
使用belongsToMany()函数
4.2 关联查询
public function role()
{
$user = User::find(1);
dump($user->roles);
}
可以直接获取id为1的用户的角色信息
4.3 关联新增
public function role_add()
{
$user = User::find(1);
$user->roles()->save(['name'=>'管理员']);
}
这里执行了两个操作
- 向关联的角色表里添加了一条记录
- 向中间表添加了一条记录
不用手动的维护中间表, 这个还不错~~
1
1
1
1
1
1
1
1
1
1