用一对多关联的前提
多的一方的数据库表有一的一方数据库表的外键。
举例,用户获取自己的所有文章
数据表结构如下
// 用户表
user
user_id - integer // 用户主键
name - varchar // 用户名称
// 文章表
article
article_id - integer // 文章主键
title - varchar // 文章名标题
content - text // 文章内容
user_id - integer // 作者 user_id
多的一方(文章表)存在一的一方(用户表)的外键 user_id 。
一对多关联定义
用户表 user 模型:
<?php
namespace app\api\model;
class User extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'user_id';
// 获取用户详情以及用户的所有文章
public static function getDetail(int $user_id)
{
return self::get($user_id, 'articles');
}
// 一对多获取用户的文章
public function articles()
{
// 完整写法
return $this->hasMany('Article', 'user_id', 'user_id');
}
}
hasMany 方法参数如下:
hasMany('关联模型', '关联模型外键', '当前模型主键');
除了关联模型外,其它参数都是可选。
- 关联模型(必须):模型名或者模型类名
- 关联模型外键:关联模型外键,默认的外键名规则是当前模型名+
_id
- 当前模型主键:当前模型主键,一般会自动获取也可以指定传入
实例演示
shop_article 表
shop_user 表
演示1
获取 user_id 为 1 的用户详情以及用户的所有文章
用户 User 控制器
<?php
namespace app\api\controller;
use app\api\model\User as UserModel;
class User extends Base
{
public function detail()
{
$user_id = 1;
$detail = UserModel::getDetail($user_id);
echo '<pre>';
var_dump($detail);
echo '</pre>';
}
}
用户表 User 模型
<?php
namespace app\api\model;
class User extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'user_id';
// 获取用户详情以及用户的所有文章
public static function getDetail(int $user_id)
{
return self::get($user_id, 'articles');
}
// 一对多获取用户的文章
public function articles()
{
// 完整写法
return $this->hasMany('Article', 'user_id', 'user_id');
}
}
user 控制器 detail 方法输出
object(app\api\model\User)#41 (2) {
["data"]=>
array(4) {
["user_id"]=>
int(1)
["name"]=>
string(5) "admin"
["create_time"]=>
int(1688452509)
["update_time"]=>
int(1688452509)
}
["relation"]=>
array(1) {
["articles"]=>
object(think\model\Collection)#50 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\Article)#45 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(1)
["title"]=>
string(12) "测试标题"
["content"]=>
string(12) "测试内容"
["user_id"]=>
int(1)
["create_time"]=>
int(1689401566)
["update_time"]=>
int(1689401566)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\Article)#46 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(2)
["title"]=>
string(13) "测试标题1"
["content"]=>
string(13) "测试内容1"
["user_id"]=>
int(1)
["create_time"]=>
int(1689498967)
["update_time"]=>
int(1689498967)
}
["relation"]=>
array(0) {
}
}
}
}
}
}
单条查询输出的是 User 模型实例,User 模型实例的 relation 属性(关联数组)保存着关联模型,在该关联数组中,关联方法名 articles 作为键名,关联查询结果作为键值(对一关联查询返回模型实例,对多关联查询返回结果集对象)。
使用的 SQL 如下
SELECT * FROM `shop_user` WHERE `user_id` = 1 LIMIT 1
SELECT * FROM `shop_article` WHERE `user_id` = 1
获取当前用户的文章,访问 articles(关联方法名) 属性即可,如下
<?php
namespace app\api\controller;
use app\api\model\User as UserModel;
class User extends Base
{
public function detail()
{
$user_id = 1;
$detail = UserModel::getDetail($user_id);
echo '<pre>';
var_dump($detail->articles);
echo '</pre>';
}
}
输出如下
object(think\model\Collection)#50 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\Article)#45 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(1)
["title"]=>
string(12) "测试标题"
["content"]=>
string(12) "测试内容"
["user_id"]=>
int(1)
["create_time"]=>
int(1689401566)
["update_time"]=>
int(1689401566)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\Article)#46 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(2)
["title"]=>
string(13) "测试标题1"
["content"]=>
string(13) "测试内容1"
["user_id"]=>
int(1)
["create_time"]=>
int(1689498967)
["update_time"]=>
int(1689498967)
}
["relation"]=>
array(0) {
}
}
}
}
演示2
获取所有用户的用户详情以及用户的所有文章
用户 User 控制器
<?php
namespace app\api\controller;
use app\api\model\User as UserModel;
class User extends Base
{
// 获取所有用户的用户详情以及用户的所有文章
public function list()
{
$list = UserModel::getList();
echo '<pre>';
var_dump($list);
echo '</pre>';
}
}
用户表 User 模型
<?php
namespace app\api\model;
class User extends Base
{
protected $pk = 'user_id';
// 获取所有用户的用户详情以及用户的所有文章
public static function getList()
{
return self::with('articles')->select();
}
// 一对多获取用户的文章
public function articles()
{
// 完整写法
return $this->hasMany('Article', 'user_id', 'user_id');
}
}
user 控制器 list 方法输出
object(think\model\Collection)#44 (1) {
["items":protected]=>
array(3) {
[0]=>
object(app\api\model\User)#41 (2) {
["data"]=>
array(4) {
["user_id"]=>
int(1)
["name"]=>
string(5) "admin"
["create_time"]=>
int(1688452509)
["update_time"]=>
int(1688452509)
}
["relation"]=>
array(1) {
["articles"]=>
object(think\model\Collection)#52 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\Article)#47 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(1)
["title"]=>
string(12) "测试标题"
["content"]=>
string(12) "测试内容"
["user_id"]=>
int(1)
["create_time"]=>
int(1689401566)
["update_time"]=>
int(1689401566)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\Article)#48 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(2)
["title"]=>
string(13) "测试标题1"
["content"]=>
string(13) "测试内容1"
["user_id"]=>
int(1)
["create_time"]=>
int(1689498967)
["update_time"]=>
int(1689498967)
}
["relation"]=>
array(0) {
}
}
}
}
}
}
[1]=>
object(app\api\model\User)#42 (2) {
["data"]=>
array(4) {
["user_id"]=>
int(2)
["name"]=>
string(0) ""
["create_time"]=>
int(1689732287)
["update_time"]=>
int(1689732287)
}
["relation"]=>
array(1) {
["articles"]=>
object(think\model\Collection)#53 (1) {
["items":protected]=>
array(0) {
}
}
}
}
[2]=>
object(app\api\model\User)#43 (2) {
["data"]=>
array(4) {
["user_id"]=>
int(3)
["name"]=>
string(6) "测试"
["create_time"]=>
int(1690355199)
["update_time"]=>
int(1690355199)
}
["relation"]=>
array(1) {
["articles"]=>
object(think\model\Collection)#54 (1) {
["items":protected]=>
array(0) {
}
}
}
}
}
}
多条查询返回的是 Collection(结果集)对象,Collection 对象的 item 属性保存着所有用户模型实例,每个用户模型实例的 relation 属性 (关联数组)属性保存着关联模型实例,关联方法名 articles 作为键名,结果集对象作为键值,结果集对象的 items 属性(索引数组)保存着关联查询结果。
使用的 SQL 如下
SELECT * FROM `shop_user`
SELECT * FROM `shop_article` WHERE `user_id` IN (1,2,3)
获取每个用户的所有文章,访问 articles(关联方法名) 属性即可,如下
<?php
namespace app\api\controller;
use app\api\model\User as UserModel;
class User extends Base
{
public function list()
{
$list = UserModel::getList();
foreach ($list as $user) {
echo '<pre>';
var_dump($user->articles);
echo '</pre>';
}
}
}
user 控制器 list 方法输出如下
object(think\model\Collection)#52 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\Article)#47 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(1)
["title"]=>
string(12) "测试标题"
["content"]=>
string(12) "测试内容"
["user_id"]=>
int(1)
["create_time"]=>
int(1689401566)
["update_time"]=>
int(1689401566)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\Article)#48 (2) {
["data"]=>
array(6) {
["article_id"]=>
int(2)
["title"]=>
string(13) "测试标题1"
["content"]=>
string(13) "测试内容1"
["user_id"]=>
int(1)
["create_time"]=>
int(1689498967)
["update_time"]=>
int(1689498967)
}
["relation"]=>
array(0) {
}
}
}
}
object(think\model\Collection)#53 (1) {
["items":protected]=>
array(0) {
}
}
object(think\model\Collection)#54 (1) {
["items":protected]=>
array(0) {
}
}