ThinkPHP6.0學習筆記-模型操做

ThinkPHP模型

模型定義

app目錄下建立Model目錄,便可建立模型文件php

定義一個和數據庫表相匹配的模型react

use think\Model;

class User extends Model
{
    
}

User會自動匹配對於數據庫中的數據表tp_usersql

模型命名後綴,是爲了防止關鍵字衝突,能夠開啓應用類後綴:建立Class UserModelthinkphp

use think\Model;

class UserModel extends Model
{
  //指向數據表
 protected $name = 'user';
 protected $table = 'tp_user';
}

模型類的定義須要去除表前綴,採用駝峯式命名首字母大寫數據庫

tp_user 		==>		User
tp_user_type	==> 	UserType

建立於數據表相匹配的模型類後,能夠在使用User::*方法來調用數據庫進行操做json

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';

在控制器中調用模型操做,發生重名能夠設置別名app

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數組的namescore數據。


最佳操做實踐

新增操做:

新增數據的最佳實踐原則:使用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        =   'chengguo@gmail.com';
    $user->price        =    100 ;
    $user->uid          =    0000;
    $user->details      =    '000';
    
    $user->save();
}

上述的只是一個普通方法,除此還有傳遞數據數組的方式

public function index()
{
    $user = new model\UserModel();
    $data = [
        'username'     =>   '諸葛大力',
        'password'     =>   'gouzaizai',
        'gender'       =>   '女',
        'email'        =>   'chengguo@gmail.com',
        '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` = 'chengguo@gmail.com' , `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'=>'thinkphp@qq.com'],
   ['name'=>'onethink','email'=>'onethink@qq.com']
];
$user->saveAll($list);

saveAll方法新增數據返回的是包含新增模型(帶自增ID)的數據集對象。

saveAll方法新增數據默認會自動識別數據是須要新增仍是更新操做,當數據中存在主鍵的時候認爲是更新操做。

靜態方法 create() *
$user = UserModel::create([
    'username' => '李白',
    'password' => '123',
    'gender' => '男',
    'email' => 'libai@163.com',
    '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' => 'libai@163.com',
    'price' => 100,
    'details' => '123',
    'uid' => 1011
];
$user->allowField(['username'])->save($data);

使用saveAll()方法能夠批量修改數據,返回被修改數據集;批量saveAll()更新只能夠經過主鍵來進行

靜態方法::update()更新

$data = [    'username=> '李白',
    'password' => '123',
    'gender' => '男',
    'email' => 'libai@163.com',
    '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' => 'LIBai@163.com',
    '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字段的數據,所以能夠很好的避免表單的非法查詢條件傳入,在這個示例中僅能使用namecreate_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_timeupdate_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' 	=> 'LIBai@163.com',
   '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'    => 'thinkphp@qq.com',
    'nickname '=> '流年',
];
$user->save();

具體的請參考官方文檔JSON部分


模型軟刪除

在實際項目中,對數據頻繁使用刪除操做會致使性能問題,軟刪除的做用就是把數據加上刪除標,而不是真正的刪除,同時也便於須要的時候進行數據的恢復。

要使用軟刪除功能,須要引入SoftDeletetrait,例如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}
外鍵:
關聯鍵:中間表的當前模型關聯鍵名

參考官方文檔

相關文章
相關標籤/搜索