ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
>[info] **主表建立关联关系** >hasOne('关联从表模型名','从表外键名','主表主键名',\['模型别名定义'\],'join类型,默认`INNER`'); 返回HasOne类对象 | 参数 | 说明 | | --- | --- | | model | 关联的从表模型名,该参数被定义时,与之对应当前模块下必须有个与此参数名相同的模块文件;如果不是前模块而是跨模块,此参数为带有完整的命名空间的模型名 | | foreignKey | 从表外键名,默认为:当前模型名_id | | localKey | 主表的主键名 | | alias | 定义此模型的别名.`5.0.5+`版本开始,模型别名定义参数已经废弃。 | | joinType | join类型,默认`INNER` | ## **定义** 定义一对一关联,例如,一个用户都有一个个人资料, user表(主表) ![](https://img.kancloud.cn/b8/10/b8105f74178cb588590809c2de5ce7e1_251x49.png) profile(从表) ![](https://img.kancloud.cn/04/68/0468a56482248422c8bca17d3980f272_367x43.png) **主表建立关联关系例子:** 定义主表对应的`User`模型如下: ~~~ namespace app\index\model; use think\Model; class User extends Model { //定义关联方法 public function userRelationProfile() { return $this->hasOne('Profile'); //默认情况下, 我们使用的是`user_id`作为外键关联,如果不是的话则需要在关联定义的时候指定 //return $this->hasOne('Profile','uid'); //`V5.0.3+`版本开始,可以支持为关联模型定义需要查询的字段;如果使用的是`join`方式的关联,不支持指定field字段。 //return $this->hasOne('Profile')->field('id,name,email'); //跨模块需要完整的命名空间 //return $this->hasOne('\app\api\Profile'); } } ~~~ ## **关联查找** 在主表的User模型的profile方法定义好关联之后,就可以使用下面的方法获取关联数据: ~~~ $user=\app\index\model\User::get(1); echo $user->id; echo $user->username; //注意这里和with的参数一致 即定义的驼峰样式的关联方法名称转成小写+_组成的字符串 echo $user->user_relation_profile->phone; //或者 $user=\app\index\model\User::with('user_relation_profile')->find(1); echo $user->id; echo $user->username; echo $user->user_relation_profile->phone; //::with()返回的是Query对象 //::get()返回的是model对象 ~~~ >[danger] 有一点需要注意的是,关联方法的命名规范是驼峰法,而关联属性则一般是小写+下划线的方式,系统在获取的时候会自动转换对应,读取`user_profile`关联属性则对应的关联方法应该是`userProfile`。 如果要根据关联表的查询条件查询当前模型的数据,可以使用`hasWhere`方法,例如: ~~~ $user = \app\index\model\User::hasWhere('user_relation_profile',['phone'=>'0086-010-66778899'])->find(); echo $user->username; ~~~ ## **关联新增** 系统会自动把当前模型的主键传入profile模型。 ``` //id为2则自动解析为user_id和下面的数据一并自动插入到profile中 $user = User::get(2); // 如果还没有关联数据 则进行新增 注意userRelationProfile是我们定义的关联方法 $user->userRelationProfile()->save(['mobile' => '12345678909','phone' => '0825-123456']); ``` ![](https://img.kancloud.cn/ff/33/ff33011a992f35d8a27f6b02805d07e6_382x21.png) 一般是更新模型时也同时更新关联模型 ``` $user =model('user'); $user->pwd = 'qwer123456'; $user->username = 'dash'; if ($user->save()) { // 写入关联数据 $profile['phone'] = '0825-123456'; $profile['mobile'] = '12334178908'; $user->userRelationProfile()->save($profile); return $user->username . ' 新增成功'; } else { return $user->getError(); } ``` ## **关联更新** 和新增一样使用`save`方法进行更新关联数据。 ~~~ $user = User::get(1); $user->user_relation_profile->phone= 18700000000; $user->user_relation_profile->save(); // 或者 $user->user_relation_profile->save(['phone' => 18700000000]); ~~~ 一般的业务需求也是主表和从表同时更新 ~~~ public function update($id) { $user = model('user')::get($id); $user->username = 'tom'; if ($user->save()) { // 更新关联数据 $user->user_relation_profile->phone=18700000000; $user->user_relation_profile->save(); return $user->phone. ' 更新成功'; } else { return $user->getError(); } } 访问:http://tp5.com/user/update/2 进行更新 ~~~ ## 绑定属性到父模型(`V5.0.4+`) 可以在定义关联模型的时候使用bind方法绑定属性到父模型,例如: ~~~ namespace app\index\model; use think\Model; class User extends Model { //定义关联方法 public function userRelationProfile() { return $this->hasOne('Profile','user_id')->bind(['dianhua'=>'phone', 'mobile'.'profile_id'=>'id']); } } ~~~ 这样在获取数据的时候可以直接拿到关联模型的数据了 ``` $user=\app\index\model\User::get(1); echo $user->id; echo $user->username; echo $user->dianhua; echo $user->mobile; echo $user->profile_id; ``` 绑定关联属性不影响原有关联属性的读取,绑定关联模型的属性支持读取器。 > 如果不是预载入查询,请使用模型的appendRelationAttr方法追加属性。