ThinkPHP6.0學習筆記-模型操作
ThinkPHP模型
模型定義
在app
目錄下建立Model
目錄,即可建立模型檔案
定義一個和資料庫表相匹配的模型
use think\Model;
class User extends Model
{
}
User
會自動匹配對於資料庫中的資料表tp_user
模型命名字尾,是為了防止關鍵字衝突,可以開啟應用類字尾:建立
Class UserModel
use think\Model; class UserModel extends Model { //指向資料表 protected $name = 'user'; protected $table = 'tp_user'; }
模型類的定義需要去除表字首,採用駝峰式命名首字母大寫
tp_user ==> User
tp_user_type ==> UserType
創建於資料表相匹配的模型類後,可以在使用User::*
方法來呼叫資料庫進行操作
namespace app\controller; use think\facade\Db; use app\model; class DataTest { public function index() { $user = model\User::select(); return json($user); } }
設定模型
模型中預設的主鍵為id
,也可以在模型類中設定主鍵欄位名$pk
protected $pk = 'uid';
在控制器中呼叫模型操作,發生重名可以設定別名
use app\model\User as UserModel;
模型類中可以定義指向資料庫表
protected $table = 'tp_user'; //包含字首
protected $name = 'user'; //不含字首
模型類初始化操作(控制器也有),但是必須設定static
靜態方法
protected static funtion init()
{
echo "初始化";
}
模型設定屬性:
屬性 | 描述 |
---|---|
name | 指向資料表名(無字首),預設為當前模型名 |
table | 資料表 |
suffix | 資料表字尾(預設為空) |
pd | 設定資料表主鍵欄位名(預設為id ) |
connection | 資料庫連線(預設載入資料庫配置database.php ) |
query | 模型使用的查詢類名稱 |
field | 指定允許操作的欄位(支援陣列) |
schema | 模型對應資料表字段和型別 |
type | 模型需要自動轉換的欄位和型別 |
strict | 是否嚴重區分欄位大小(預設true) |
disuse | 資料表廢棄欄位 |
模型欄位
模型的資料欄位和對應的資料表字段是對應的,預設會自動獲取(以及型別),自動獲取的過程會加一次查詢操作(浪費資源),thinkphp支援自定義欄位資訊。
$schema = [
'[欄位名]' => '[欄位型別]';
]
schema
需要定義整個資料表字段,對單個欄位定義需要自動轉換的型別可以使用type
如果需要廢棄(忽略)資料表中的欄位,可以使用$disuse
來定義
protected $disuse = [‘type’,'status'];
獲取資料
$user = User::find(1);
echo $user->create_time;
echo $user->name;
由於模型類實現了ArrayAccess
介面,所以可以當成陣列使用。
$user = User::find(1);
echo $user['create_time'];
echo $user['name'];
如果你是在模型內部獲取資料的話,需要改成:
$user = $this->find(1);
echo $user->getAttr('create_time');
echo $user->getAttr('name');
模型賦值、 例項化
給模型物件賦值
$user = new User() ;
$user->table = 'tp_user';
$user->score = 100 ;
上述程式碼會將模型物件打包賦值給$user
,可以對其封裝的模型物件進行操作“修改器”
同時也可以使用
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user = new User($data);
或者使用
$user = new User();
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user->data($data);
data
方法支援使用修改器
$user = new User();
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user->data($data, true);
如果需要對資料進行過濾,可以使用
$user = new User();
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user->data($data, true, ['name','score']);
表示只設置data
陣列的name
和score
資料。
最佳操作實踐
新增操作:
新增資料的最佳實踐原則:使用create
靜態方法新增資料,使用saveAll
批量新增數。
刪除操作:
刪除的最佳實踐原則是:如果刪除當前模型資料,用delete
方法,如果需要直接刪除數,使用destroy
靜態方法。
更新操作:
更新的最佳實踐原則是:如果需要使用模型事件,那麼就先查詢後更新,如果不需要使用事件或者不查詢直接更新,直接使用靜態的Update
方法進行條件更新,如非必要,儘量不要使用批量更新。
新增-save()
模型資料的新增和資料庫的新增資料有所區別,資料庫的新增只是單純的寫入給定的資料,而模型的資料寫入會包含修改器、自動完成以及模型事件等環節,資料庫的資料寫入參考資料庫章節。
第一步:例項化模型物件
$user = new UserModel();
$user = new \app\model\UserModel();
第二步:新增資料
public function index()
{
$user = new model\UserModel();
$user->username = '諸葛大力';
$user->password = 'gouzaizai';
$user->gender = '女';
$user->email = '[email protected]';
$user->price = 100 ;
$user->uid = 0000;
$user->details = '000';
$user->save();
}
上述的只是一個普通方法,除此還有傳遞資料陣列的方式
public function index()
{
$user = new model\UserModel();
$data = [
'username' => '諸葛大力',
'password' => 'gouzaizai',
'gender' => '女',
'email' => '[email protected]',
'price' => 100 ,
'uid' => 0000,
'details' => '000',
];
$user->save($data);
}
allowField()
限制寫入允許欄位
$user
// 限制只允許寫入‘username、password’欄位
->allowField(['username','password'])
->save($data);
replace()
新增
實現REPLACE into
新增(修改新增)
$user->replace()->save($data);
如果$data
資料表已存在會更新;
REPLACE INTO `tp_user` SET `id` = 301 , `username` = '諸葛大力' , `password` = 'gouzaizai' , `gender` = '女' , `email` = '[email protected]' , `price` = 100 , `uid` = 0 , `details` = '000' , `create_time` = '2020-04-10 11:40:20.660840' , `update_time` = '2020-04-10 11:40:20.660840'
獲取自增ID
$user->id;
$user->uid;
……
批量新增資料saveAll()
*
可以批量添資料,返回新增陣列
$user = new User;
$list = [
['name'=>'thinkphp','email'=>'[email protected]'],
['name'=>'onethink','email'=>'[email protected]']
];
$user->saveAll($list);
saveAll方法新增資料返回的是包含新增模型(帶自增ID)的資料集物件。
saveAll
方法新增資料預設會自動識別資料是需要新增還是更新操作,當資料中存在主鍵的時候認為是更新操作。
靜態方法 create()
*
$user = UserModel::create([
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => '[email protected]',
'price' => 100,
'details' => '123',
'uid' => 1011
], ['username', 'password', 'details'], false);
引數 1 是新增資料陣列,必選
引數 2 是允許寫入的欄位,可選
引數 3 為是否 replace 寫入,預設 false 為 Insert 寫入
新增資料的最佳實踐原則:使用create
方法新增資料,使用saveAll
批量新增資料。
刪除-delete()
刪除當前模型
$user = new User();
$user->delete();
根據主鍵刪除
User::destroy(1);
User::destroy([1,2,3]);
條件刪除
User::where('id',10)->delete();
User::destroy(function($query){
$query->where('id',10);
});
刪除的最佳實踐原則是:如果刪除當前模型資料,用delete
方法,如果需要直接刪除資料,使用destroy
靜態方法。
更新
使用find()
方法獲取資料,通過save()
方法提交修改
$user = new model\UserModel();
$data = [
'username' => '諸葛大力',
'gender' => '女'
];
$user->find(305)->save($data);
使用where()
方法結合find()
方法設定查詢條件並獲取資料
$user = new model\UserModel();
$data = [
'username' => '齊天大聖'
];
$user->where('username','孫悟空')
->find()->save($data);
save()
只會更新資料有區別的地方;強制使用save()
更新資料需要使用force()
Db::raw()
執行SQL函式方法同樣可以實現更新
$user = model\UserModel::find(305);
$user->price = Db::raw('price+10');
$user->save();
使用allowField()
方法,允許要更新的欄位
$user = model\UserModel::find(305);
$data = [
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => '[email protected]',
'price' => 100,
'details' => '123',
'uid' => 1011
];
$user->allowField(['username'])->save($data);
使用saveAll()
方法可以批量修改資料,返回被修改資料集;批量saveAll()
更新只可以通過主鍵來進行
靜態方法::update()
更新
$data = [ 'username=> '李白',
'password' => '123',
'gender' => '男',
'email' => '[email protected]',
'price' => 100,
'details' => '123',
'uid' => 1011
];
model\UserModel::update($data,['id'=> 304],['username']);
引數 1 是資料陣列,必選
引數 2 更新條件,可選
引數 3 是允許寫入的欄位,可選
save()
模型的新增、更新都需要
save()
進行執行,具有自動識別;例項化模型後呼叫
save()
表示新增,查詢資料後呼叫save()
表示修改
更新的最佳實踐原則是:如果需要使用模型事件,那麼就先查詢後更新,如果不需要使用事件或者不查詢直接更新,直接使用靜態的Update
方法進行條件更新,如非必要,儘量不要使用批量更新。
查詢
模型普通查詢
-
使用
find()
通過主鍵查詢想要的資料(可以在模型類中設定主鍵欄位)呼叫
find()
方法是,如果資料不存在返回Null,使用findOrEmpty()
方法,資料不存返回空模型使用
isEmpty()
方法判斷是否為空模型 -
使用
where()
進行條件篩選查詢 -
使用
select()
方法,查詢多條指定主鍵的欄位,不指定就是全部欄位$user = model\UserModel::select([304,305]); foreach ($user as $key=>$value) { echo $value->username; }
-
支援查詢構造器的各種方法
模型動態查詢
getBy[欄位名]
:可以獲取對應欄位的value(駝峰命名,欄位首字母大寫)
$user = model\UserModel::getByUsername('李白');
模型聚合查詢
支援max
min
sum
count
avg
等方法
UserModel::max('price');
模型分批查詢
支援使用chunk()
進行分批處理資料
User::chunk(100, function ($users) {
foreach($users as $user){
// 處理user模型物件
}
});
模型遊標查詢
支援使用cursor()
方法進行遊標查詢,返回生成器物件
foreach(User::where('status', 1)->cursor() as $user){
echo $user->name;
}
user
變數是一個模型物件例項。
模型查詢的最佳實踐原則是:在模型外部使用靜態方法進行查詢,內部使用動態方法查詢,包括使用資料庫的查詢構造器。
模型獲取器
獲取器的作用是對模型例項的資料做出自動處理
每一個獲取器對應模型的一個特殊方法,方法要求public
獲取器命名規範
get[FieldName]Attr()
,FieldName為資料表字段的駝峰轉換,定義了獲取器自動觸發
- 模型的資料物件取值操作
$model->field_name
- 模型的序列化輸出操作
$model->toArray()
- 顯式呼叫
getAttr
方法$this->getAttr('field_name')
獲取器常見場景以及基本使用
- 時間日期欄位的格式化輸出
- 集合或列舉型別的輸出
- 數字狀態欄位的輸出
- 組合欄位的輸出
// 狀態值的轉換輸出
// 模型類
public function getStatusAttr($value)
{
$status = [-1=>'刪除' , 0=>'禁用' , 1=>'正常' , 2=>"待稽核"];
return $status[$value];
}
// 控制端
$user = model\UserModel::find(19);
return $user->status;
通俗理解:
在控制端正常的檢視欄位值,模型類定義一個獲取器(一個欄位可以對應一個模型類中的特殊方法獲取器方法)),獲取器就會對控制端的欄位查詢進行獲取並進行自定義的處理方法。
獲取器還可以定義資料表不存在的欄位,在控制端使用者可以正常的按照欄位名讀取的方式來訪問
<?php
namespace app\model;
use think\Model;
class User extends Model
{
public function getStatusTextAttr($value,$data)
{
$status = [-1=>'刪除',0=>'禁用',1=>'正常',2=>'待稽核'];
return $status[$data['status']];
}
}
獲取器方法的第二個引數傳入的是當前的所有資料陣列。
我們就可以直接使用status_text欄位的值了,例如:
$user = User::find(1);
echo $user->status_text; // 例如輸出“正常”
這裡也就是為了解決多種處理方法並規避衝突的寫法;因為如果獲取器定義以後就無法在控制端獲原始的欄位值,不過也還有另外一種getData()
方法獲得原始欄位值:
$user = User::find(1);
// 通過獲取器獲取欄位
echo $user->status;
// 獲取原始欄位資料
echo $user->getData('status');
// 獲取全部原始資料
dump($user->getData());
動態獲取器
可以支援對模型使用動態獲取器,無需在模型類中定義獲取器方法,在控制端使用動態獲取器:
$user = model\UserModel::find(19)
->withAttr('status',function($value,$data){
$status = [
-1=>'刪除',0=>'禁用',
1=>'正常',2=>'待稽核'
];
return $status[$value];
});
echo $user->status;
withAttr
方法支援多次呼叫,定義多個欄位的獲取器。另外注意,withAttr
方法之後不能再使用模型的查詢方法,必須使用Db類的查詢方法。
模型修改器
模型修改器的左右:對模型設定物件的值進行處理
在新增資料的時候,可以利用修改器對資料進行格式化、轉換等處理;處理資料新增,還有資料更新也可能觸發修改器
模型修改器命名規範:
setFieldNameAttr()
ps:修改器只對模型方法有效
public function setEmailAttr($value)
{
return strtolower($value);
}
$user = model\UserModel::create([
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => '[email protected]',
'price' => 100,
'details' => '123',
'uid' => 1011
], ['username', 'password', 'details','email'], false);
echo $user->save();
查詢範圍
在模型類建立一個封裝的查詢和寫入方法,有便於控制端呼叫
查詢封裝方法 scope()
字首scope
,字尾自定義,在呼叫時吧字尾當做引數即可。
public function scopeMale($query)
{
$query->where('gender','男')
->field('id,username,gender,email')
->limit(5);
}
$user = model\UserModel::scope('male')->select();
return "<hr>".Db::getLastSql()."<hr>".$user;
public function scopeEmail($query, $value)
{
$query->where('email','like','%'.$value.'%');
}
$user = UserModel::scope('email','xiao')->select();
return "<hr>".Db::getLastSql()."<hr>".$user;
scope()
的第一個引數是呼叫的封裝方法,第二個引數是封裝方法可以接收的資料
支援多個查詢封裝方法連綴呼叫
$user = UserModel::scope('email','xiao')
->scope('price',80)
->select();
return "<hr>".Db::getLastSql()."<hr>".$user;
在使用查詢範圍
scope()
後,指定使用find()
select()
查詢;在模型類中的查詢封裝方法中可以使用包括修改器、獲取器等在內的模型操作方法。
public function getGenderAttr($value,$data) { $gender = ['男'=>'純爺們','女'=>'小姑娘']; return $gender[$value]; } public function scopeMale($query) { $query->where('gender','男') ->field('id,username,gender,email') ->limit(5); }
全域性查詢範圍
支援在模型中設定globaScope
屬性,定義全域性查詢範圍
class User extends Model
{
// 定義全域性的查詢範圍
protected $globalScope = ['status'];
public function scopeStatus($query)
{
$query->where('status',1);
}
}
然後,執行下面的程式碼:
$user = User::find(1);
最終的查詢條件會是
status = 1 AND id = 1
如果需要動態關閉所有的全域性查詢範圍,可以使用:
// 關閉全域性查詢範圍
User::withoutGlobalScope()->select();
可以使用withoutGlobalScope
方法動態關閉部分全域性查詢範圍。
User::withoutGlobalScope(['status'])->select();
模型搜尋器
搜尋器用於封裝欄位或搜尋標識的表示式,類似查詢範圍
一個搜尋器對應模型的一個特殊方法
命名規範
search[FieldName]Attr()
User模型定義name
欄位和時間欄位的搜尋器,可以使用:
class User extends Model
{
public function searchNameAttr($query, $value, $data)
{
$query->where('name','like', $value . '%');
}
public function searchCreateTimeAttr($query, $value, $data)
{
$query->whereBetweenTime('create_time', $value[0], $value[1]);
}
}
然後,我們可以使用下面的查詢
User::withSearch(['name','create_time'], [
'name' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1
])->select();
最終生成的SQL語句類似於
SELECT * FROM `think_user` WHERE `name` LIKE 'think%' AND create_time` BETWEEN '2018-08-01 00:00:00' AND '2018-08-05 00:00:00'
可以看到查詢條件中並沒有status
欄位的資料,因此可以很好的避免表單的非法查詢條件傳入,在這個示例中僅能使用name
和create_time
條件進行查詢。
事實上,除了在搜尋器中使用查詢表示式外,還可以使用其它的任何查詢構造器以及鏈式操作。
例如,你需要通過表單定義的排序欄位進行搜尋結果的排序,可以使用
class User extends Model
{
public function searchNameAttr($query, $value, $data)
{
$query->where('name','like', $value . '%');
if (isset($data['sort'])) {
$query->order($data['sort']);
}
}
public function searchCreateTimeAttr($query, $value, $data)
{
$query->whereBetweenTime('create_time', $value[0], $value[1]);
}
}
然後,我們可以使用下面的查詢
User::withSearch(['name','create_time', 'status'], [
'name' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1,
'sort' => ['status'=>'desc'],
])
->select();
最終查詢的SQL可能是
SELECT * FROM `think_user` WHERE `name` LIKE 'think%' AND `create_time` BETWEEN '2018-08-01 00:00:00' AND '2018-08-05 00:00:00' ORDER BY `status` DESC
你可以給搜尋器定義欄位別名,例如:
User::withSearch(['name'=>'nickname','create_time', 'status'], [
'nickname' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1,
'sort' => ['status'=>'desc'],
])
->select();
搜尋器通常會和查詢範圍進行比較,搜尋器無論定義了多少,只需要一次呼叫,查詢範圍如果需要組合查詢的時候就需要多次呼叫
模型資料集
資料集直接繼承collection
類,和資料的資料集方式一樣、操作一樣。
參照官方技術文件
模型自動時間戳
系統支援自動寫入建立和更新的時間戳欄位(預設會關閉),具體配置方法:
-
全域性開啟:在
database.php
檔案中修改auto_timestamp
為truely -
在模型類中單獨開啟自動時間戳:
$autoWriteTimestamp
class User extends Model { protected $autoWriteTimestamp = true; }
也或者單獨關閉自動時間戳
class User extends Model { protected $autoWriteTimestamp = false; }
配置開啟後會自動新增自動時間戳寫入
create_time
和update_time
兩個
端,預設的型別是int,如果是時間型別,可以設定如下
protected $autoWriteTimestamp = [自動時間戳欄位]
同時也可以自定義兩個自動時間戳:
protected $createTime = '[欄位]';
protected $updateTime = '[欄位]';
只讀欄位
在模型類中定義readonly
屬性:靜態
protected $readonly = ['欄位1','欄位2',……]
動態設定制度欄位:
$user->readonly(['欄位1',……])->save();
系統轉換
系統可以通過模型端設定寫入或讀取時對欄位型別進行轉換type
php rotected $type = [ 'price' => 'integer', 'status' => 'boolean', ;
設定廢棄欄位 $disuse
JSON欄位 *
資料庫JSON
資料庫寫入JSON欄位,直接通過陣列方式即可完成:
data = [
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => '[email protected]',
'price' => 100,
'details' => '123',
'list' => ['username'=>李白,'gender'=>'女']
];
Db::table('tp_user')
->json(['list']) // 定義list欄位為json型別欄位
->insert($data)
查詢資料,需要轉換JSON資料格式:
Db::table('tp_user')->json(['list'])->find(288);
將JSON欄位裡的資料作為查詢條件
$user = Db::table('tp_user')->json(['list'])->where('list-username','李白')->find();
修改JSON欄位資料
$data['list'] = ['username'=>'李白','gender'=>'男'];
Db::table('tp_user')->json(['list'])->where('id',220)->update($data);
模型JSON
設定寫入JSON欄位的字元欄位:
protetced $json = ['list'];
使用模型方法新增JSON資料的欄位
$user = new User;
$user->name = 'thinkphp';
$user->info = [
'email' => '[email protected]',
'nickname '=> '流年',
];
$user->save();
具體的請參考官方文件JSON部分
模型軟刪除
在實際專案中,對資料頻繁使用刪除操作會導致效能問題,軟刪除的作用就是把資料加上刪除標,而不是真正的刪除,同時也便於需要的時候進行資料的恢復。
要使用軟刪除功能,需要引入SoftDelete
trait,例如User模型按照下面的定義就可以使用軟刪除功能:
use SoftDelete ;
rotected $deleteTime = 'delete_time';
delete_time
預設為Null,型別為時間戳型別,用於記錄資料的刪除時間。
確定開啟軟刪除和欄位後
// 軟刪除
User::destroy(1);
// 真實刪除
User::destroy(1,true);
$user = User::find(1);
// 軟刪除
$user->delete();
// 真實刪除
$user->force()->delete();
軟刪除後系統會忽略該條資料,模型會自動遮蔽資料
-
使用
withTrashed()
取消遮蔽軟刪除的資料 -
使用
onlyTrashend()
可以查詢被軟刪除的資料 -
使用
restore()
可以恢復被軟刪除的資料 -
如果需要強制刪除,需要使用
force()
強制安排
模型和資料庫的事件
資料庫事件
執行增刪改查操作的時候,可以同時出發一些事件來執行額外的操作;額外的操作事件可以部署在構造方法中等待啟用後執行;資料庫事件方法是Db::event('事件名','執行函式')
事件名 | 描述 |
---|---|
before_select | select 查詢前回調 |
before_find | find 查詢前回調 |
after_insert | insert 操作後回撥 |
after_update | update 操作後回撥 |
after_delete | delete 操作後回撥 |
一般情況下,資料庫事件解除安裝控制器端的初始化方法裡,有利於統一管理
public function initialize()
{
Db::event('before_select', function($query){
echo "執行了批量的查詢操作"
});
}
模型事件
事件 描述 事件方法名
after_read 查詢後 onAfterRead
before_insert 新增前 onBeforeInsert
after_insert 新增後 onAfterInsert
before_update 更新前 onBeforeUpdate
after_update 更新後 onAfterUpdate
before_write 寫入前 onBeforeWrite
after_write 寫入後 onAfterWrite
before_delete 刪除前 onBeforeDelete
after_delete 刪除後 onAfterDelete
before_restore 恢復前 onBeforeRestore
after_restore 恢復後 onAfterRestore
在模型類中使用靜態方法呼叫即可完`成事件觸發
關聯模型
關聯模型:將資料表與表之間進行關聯和物件化;
關聯方式
關聯方式 | 描述 |
---|---|
hasOne |
一對一關聯 |
belongsTo |
一對一關聯-反向 |
hasMany |
一對多關聯 |
hasOneThrough |
遠端一對一 |
hasManyThrough |
遠端一對多 |
belongsToMany |
多對多關聯 |
morphMany |
多型一對多 |
morphOne |
多型一對一 |
morphTo |
多型關聯 |
例項:
主表:tp_user
主鍵:id
附屬表:tp_profile
欄位:user_id
hobby
外來鍵user_id
主表的主鍵與附屬表的外來鍵進行關聯
一對一關聯 hasOne
-
關聯定義:
hasOne('關聯模型類名','外來鍵','主鍵')
關聯模型:
外來鍵:預設的外來鍵規則是當前的模型名+
_id
主鍵:當前模型的主鍵,自動獲取也可以指定
class UserModel extends Model { protected $table = 'tp_user'; public function profile() { return $this->hasOne(ProfileModel::class , 'user_id' , 'id'); } }
class ProfileModel extends Model { protected $table = 'tp_profile'; }
$user = model\UserModel::find(19); //return json($user->profile); return $user->profile->hobby;
使用
save()
設定關聯修改,通過主表修改附表欄位的值$user = UserModel::find(19); $user->profile->save(['hobby'=>'美女']);
->profile()
方法新增資料$user->profile()->save(['hobby'=>'靚女']);
-
相對關聯(反向)
belongsTo('關聯模型','外來鍵','關聯主鍵')
belonsTo
模式適合於附屬表關聯主表class ProfileModel extends Model { protected $table = 'tp_profile'; public function user() { return $this->belongsTo(UserModel::class , 'user_id' , id'); } }
$profile = ProfileModel::find(1); return $profile->user;
使用
hasOne()
模擬belongsTo()
$user = UserModel::hasWhere('profile',['id'=>19])->find(); // 這裡的profile是user模型勒種的方法而不是profile模型類
$user = UserModel::hasWhere('profile',function($query){ $query->where('profile.id',19); })-select();
一對多關聯-hasMany
hasMany
模式適合主表關聯附表,實現一對多查詢;與一對一查詢的主要區別就是,hasMany
可以實現查詢返回多條。
hasMany('關聯模型',['外來鍵','主鍵']);
使用->profile()
方法模式,可以對資料進行篩選
$user->profile()->where('id','>',19)->select()
呼叫屬性方式會直接返回結果,呼叫方法方式可以進行中間處理
使用has()
方法查詢關聯附表的主表內容
$user = UserModel::has('profile','>=',2)->select();
return $user;
這裡的查詢是在附表中判斷資料與主表的關聯內容
上述程式碼的主要功能:在附表中查詢與主表有兩次以上關聯的資料,例如id=19在附表中兩兩條關聯資料
使用haswhere
查詢關聯附表的處理內容(反向關聯)
$user = UserModel::hasWhere('profile',['status'=>1])->select();
return $user;
$user = UserModel::hasWhere('profile',function($query){
$query->where('status','>=',1);
})->select();
使用save()/saveAll()
新增資料
$user = UserModel::find(20);
// 新增單條資料
$user->profile()->save(['hobby'=>'計算機','status'=>'1']);
// 新增批量資料
$user->profile()->saveAll([
['hobby'=>'計算機','status'=>'1'],
['hobby'=>'遊戲機','status'=>'1']
]);
使用together()
刪除主表內容時,附表關聯的內容全部刪除
$user = UserModel::with('profile')->find(20);
$user->together(['profile'])->delete();
關聯預載入 with
普通的關聯查詢,會迴圈執行多次SQL查詢;
$list = UserModel::select([19,20,21]);
foreach($list as $user)
{
dump($user->profile);
}
採用關聯預載入的方式 ,可以減少多次查詢的耗時;
with(['關聯資料表1','關聯資料表2']);
延遲預載入:先執行
select()
再執行load()
關聯統計
使用withCount()
可以統計主表關聯附表的個數,使用profile_count
$list = UserModel::withCount(['profile'])->select([19,20,21]);
foreacth($list as $user)
{
echo $user->profile_count;
}
關聯統計的輸出採用"[關聯方法名]_count"的結構
同時支援withMax``withMin``withSum``withAvg
……
關聯輸出
使用hidden()
方法,隱藏主表字段或附表欄位
$list = Usermodel::with('profile')->select();
return json($list->hidden(['profile.status']));
使用visible()
方法,只顯示指定欄位
使用append()
方法,新增額外的欄位
多對多關聯
三張表:
access表包含了user和role表的關聯ID
belongsToMany('關聯模型','中間表',['外來鍵','關聯鍵'])
關聯模型:模型名或類名
中間表:{需要繼承Pivot}
外來鍵:
關聯鍵:中間表的當前模型關聯鍵名
參考官方文件