數據表通常相互關聯,通常簡單一些的可以使用多表聯查進行查詢,對於更加復雜的使用laravel的模型關聯查詢更加方便簡單,中文文檔,下面以省市兩張表為例
前期准備:
首先創建一個PlaceController控制器並創建index方法:
<?php namespace App\Http\Controllers\Api; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class PlaceController extends Controller { public function index(Request $request) { } }
然后創建分別創建省市兩個模型(model):
<?php namespace App\Http\Models; use Illuminate\Database\Eloquent\Model; class Province extends Model { protected $table = 'province'; protected $primaryKey = 'id'; public $timestamps = false; }
<?php namespace App\Http\Models; use Illuminate\Database\Eloquent\Model; class City extends Model { protected $table = 'city'; protected $primaryKey = 'id'; public $timestamps = false; }
准備工作結束,要使用模型關聯必須先定義關聯關系即在模型中定義關聯方法。
一對一 :hasOne()
在Province模型中定義與City模型的關聯關系city():
public function city() { return $this->hasOne('App\Http\Models\City', 'pid', 'id'); //參數一:需要關聯的子表類名,前面必須加上命名空間 參數二:子表關聯父表的字段 參數三:父表關聯子表的字段 }
在PlaceController控制器的index()中使用:
public function index(Request $request) { $place = Province::select('*') ->with(['city' => function($query) { //city對應上面province模型中定義的city方法名 閉包內是子查詢 return $query->select('*'); }]) ->where('id', 11)->first()->toArray(); //查詢id為11的省份及該省份下的第一個城市 dd($place); }
array:3 [▼ "id" => 11 "pname" => "浙江省" "city" => array:3 [▼ "id" => 89 "pid" => 11 "cname" => "台州市" ] ]
除此之外,在子查詢語句中常規的where、orderBy等方法都可以使用:
public function index(Request $request) { $cid = 99; $place = Province::select('*') ->with(['city' => function($query) use ($cid) { //傳參使用use() 多個參數($cid, $name) return $query->select('*')->where('id', $cid); }]) ->where('id', 11)->first()->toArray(); dd($place); }
array:3 [▼ "id" => 11 "pname" => "浙江省" "city" => array:3 [▼ "id" => 99 "pid" => 11 "cname" => "杭州市" ] ]
一對一定義反向關聯:belongsTo()
上面是從省份查下面的城市,反向關聯就是從城市查所屬身份,首先在city模型中定時province():
public function province() { return $this->belongsTo('App\Http\Models\Province', 'pid', 'id'); //參數一:需要關聯的父表類名,前面必須加上命名空間 注意:參數二:子表關聯父表的字段 參數三:父表關聯子表的字段 }
在控制器中使用:
public function index(Request $request) { $place = City::select('*') ->with(['province' => function($query) { return $query->select('*'); }]) ->where('id', 99)->first()->toArray(); dd($place); }
array:4 [▼ "id" => 99 "pid" => 11 "cname" => "杭州市" "province" => array:2 [▼ "id" => 11 "pname" => "浙江省" ] ]
一對多:hasMany()
在province模型中定義citys():
public function citys() { return $this->hasMany('App\Http\Models\City', 'pid', 'id'); }
在控制器中使用:
public function index(Request $request) { $place = Province::select('*') ->with(['citys' => function($query) { return $query->select('*'); }]) ->where('id', 11)->first()->toArray(); //查詢id為11的省份及該省下所有的城市 dd($place); }
array:3 [▼ "id" => 11 "pname" => "浙江省" "citys" => array:11 [▼ 0 => array:3 [▼ "id" => 89 "pid" => 11 "cname" => "台州市" ] 1 => array:3 [▶] 2 => array:3 [▶] 3 => array:3 [▶] 4 => array:3 [▶] 5 => array:3 [▶] 6 => array:3 [▶] 7 => array:3 [▶] 8 => array:3 [▶] 9 => array:3 [▶] 10 => array:3 [▶] ] ]
一對多反向關聯:belongsTo()
public function provinces() { return $this->belongsTo('App\Http\Models\Province', 'pid', 'id'); //參數一:需要關聯的父表類名,前面必須加上命名空間 注意:參數二:子表關聯父表的字段 參數三:父表關聯子表的字段 }
和一對一的反向關聯相同就不多說了
多對多:belongsToMany()
多對多比上面的都要復雜一些,需要用三張表演示,如role(角色表),role_authority(角色對應的權限表)
和 authority(所有權限表),其中role表(爺爺級)和role_authority(父級中間表)表的關聯字段是role_id, role_authority(父級中間表)表和authority(孫子級)表關聯的字段是authority_id, 那么就可以在role(爺爺級)表中定義關聯關系了:
public function role() { return $this->belongsToMany('App\Http\Models\AdminAuthority', 'admin_role_authority', 'role_id', 'authority_id'); //參數一:最低一級的表類名(孫子級) 參數二:中間表(父級)的表名 參數三:中間表與他的父級表的關聯字段 參數四:中間表與他的兒子級表的關聯字段 }
$role = AdminRole::select('*') ->with(['role' => function($query) { return $query->select('*'); }]) ->where('role_id', 22)->first()->toArray(); dd($role);
array:4 [▼ "role_id" => 22 "role_name" => "廣告設計師" "description" => "廣告設計" "role" => array:7 [▼ 0 => array:11 [▼ "authority_id" => 88 "name" => "廣告管理" "is_active" => 1 "controller" => null "action" => null "url" => null "icon" => "Hui-iconfont-dangan" "parent_id" => 0 "sort" => 3 "role_id" => 22 "pivot" => array:2 [▼ "role_id" => 22 "authority_id" => 88 ] ] 1 => array:11 [▶] 2 => array:11 [▶] 3 => array:11 [▶] 4 => array:11 [▶] 5 => array:11 [▶] 6 => array:11 [▶] ] ]
敲黑板划重點:
1.關聯模型查詢的實質總共執行兩條SQL語句,打印一下執行的SQL語句:
DB::connection()->enableQueryLog();#開啟執行日志 $role = AdminRole::select('*') ->with(['role' => function($query) { return $query->select('*'); }]) ->where('role_id', 22)->first()->toArray(); dd(DB::getQueryLog()); //獲取查詢語句、參數和執行時間
array:2 [▼ 0 => array:3 [▼ "query" => "select * from `admin_role` where `role_id` = ? limit 1" "bindings" => array:1 [▼ 0 => 22 ] "time" => 48.82 ] 1 => array:3 [▼ "query" => "select *, `admin_role_authority`.`role_id` as `pivot_role_id`, `admin_role_authority`.`authority_id` as `pivot_authority_id` from `admin_authority` inner join `admin_role_authority` on `admin_authority`.`authority_id` = `admin_role_authority`.`authority_id` where `admin_role_authority`.`role_id` in (22) ◀" "bindings" => [] "time" => 9.41 ] ]
2.在關聯查詢中,select()如果不是查出全部字段,要查詢的字段必須包含表和表之間的關聯字段才可以使用:
$role = User::select('id', 'name') //主表關聯字段是id
->with(['role' => function($query) {
return $query->select('user_id', 'name'); //子表關聯字段是user_id
}])
->first()->toArray();
3.另外還可以組合更加復雜的查詢,如三張表A、B、C,A表和B表一對一,A表和C表一對多,就可以使用leftjoin加關聯模型一對多查詢:
public function items() { return $this->hasMany('App\Http\Models\A', 'aid', 'id'); }
MallOrder::from('A as a') ->leftJoin('B as b','a.id','=','b.aid') ->with(['items' => function($query) { return $query->select('*'); }])->group()->select('*');
類似上面的組合需要打開腦洞去想去實踐了,模型關聯查詢越用越順手,越用越覺得好用,簡直是居家旅行,裝B神器!