搜尋
首頁後端開發php教程YII關聯查詢詳解

YII關聯查詢詳解

Dec 28, 2017 pm 03:29 PM
關聯查詢詳解

本文主要介紹了YII關聯查詢的相關資料,需要的朋友可以參考下。希望對大家有幫助。

一、多表關聯的設定

在我們使用AR 執行關聯查詢之前,我們需要讓AR 知道一個AR 類別是怎樣關聯到另一個的。

兩個 AR 類別之間的關係直接透過 AR 類別所代表的資料表之間的關係相關聯。 從資料庫的角度來說,表A 和B 之間有三種關係:一對多(one-to-many,例如tbl_user 和tbl_post),一對一( one-to-one 例如tbl_user 和tbl_profile)和多對多(many-to-many 例如tbl_category 和tbl_post)。 在AR 中,有四種關係:

BELONGS_TO(屬於): 如果表A 和B 之間的關係是一對多,則表B 屬於表A (例如Post 屬於User);

HAS_MANY(有多個): 如果表A 和B 之間的關係是一對多,則A 有多個B (例如User 有多個Post);

HAS_ONE(有一個) : 這是HAS_MANY 的一個特例,A 最多有一個B (例如User 最多有一個Profile);

MANY_MANY: 這個對應於資料庫中的多對多關係。 由於多數 DBMS 不直接支援 多對多 關係,因此需要有一個關聯表將 多對多 關係分割為 一對多 關係。 在我們的範例資料結構中,tbl_post_category 就是用於此目的的。在 AR 術語中,我們可以解釋MANY_MANY 為 BELONGS_TO 和 HAS_MANY 的組合。 例如,Post 屬於多個(belongs to many) Category ,Category 有多個(has many) Post.

AR 中定義關係需要覆蓋 CActiveRecord 中的 relations() 方法。此方法傳回一個關係配置陣列。每個數組元素透過如下格式表示單一的關係。


'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...additional options)



#其中VarName 是關係的名字;RelationType 指定關係類型,可以是一下四個常數之一: self::BELONGS_TO, self::HAS_ONE,self::HAS_MANY and self::MANY_MANY;ClassName 是此AR 類別所關聯的AR 類別的名字; ForeignKey 指定關係中使用的外鍵(一個或多個)。

需要弄清楚的幾點:

(1),VarName指什麼? 詳見下面例2。

(2),RelationType。共有4種,分別為

self::HAS_MANY, self::BELONGS_TO, self::MANY_MANY, self::HAS_ONE。

(3),ClassName。即關聯的另一個../model/類別名稱.php。

(4),ForeignKey。誰是誰的外鍵?

(5),附加條件

ER Diagram

#例1,一對多與多對一關係(post和user之間的關係)

1)models/Post.php


#
class Post extends CActiveRecord 
{ 
...... 
public function relations() 
{ 
return array( 
'author'=>array(self::BELONGS_TO, 'User', 'author_id'), 
); 
} 
}


其中Post與User的關係是BELONGS_TO(多對一)關係,並透過Post的author_id與User關聯。

Post中author_id是外鍵,關聯到User中。

註:此處的VarName是author,一個物件。

(2)models/User.php


#
class User extends CActiveRecord 
{ 
...... 
public function relations() 
{ 
return array( 
'posts'=>array(self::HAS_MANY, 'Post', 'author_id'), 
'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'), 
); 
} 
}


對於User,與Post的關係是屬於HAS_MANY(一對多)關係。並透過Post的author_id與Post關聯。

範例2,多對多重關係

在FailParts.php中


'Users' => array(self::MANY_MANY, 'User', 'fail_parts_user(fail_parts_id, user_id)'),


在User.php中


'FailParts' => array(self::MANY_MANY, 'FailParts', 'fail_parts_user(user_id, fail_parts_id)'),


由於兩者是多對多關係,所以要用Users,而不是User;要用FailParts,而不是FailPart。

此處的Users和FailParts,即為前面的VarName。

範例3,一對一關係

比較簡​​單,暫略。

2,關於VarName。

對於類別A.php,'VarName'=>array('RelationType', 'B', 'ForeignKey', ...additional options)
其中VarName與B基本相同。但未必完全一樣。此時就可以在A的views/A/xx.php中透過VarName來存取B及其屬性值了。

如果是一對一:A->VarName
如果是多對一:author_name = $post->Author->name;
如果一對多:$posts = $author->Post;
如果是多對多:$posts = $author->Post;//本質是拆成一對多和多對一


foreach($posts as $u){ 
$_tmp_titles[] = $u -> title; 
} 
titleStr = implode(', ', $_tmp_titles);



二、多表關聯的使用

常常在controllers裡

1,延時載入

(1)多對一

$post = Post::model()->findByPk (10);
$author = $post->author;

批註:此處本質為一對一。

(2)一對多

$user = User::model()->findByPk(10);
$posts = $user->posts;

(3)多對多

需要重點注意:兩個id有先後關係。

站在$repairInfo實例的角度,關聯關係必須是


#
'FailParts' => array(self::MANY_MANY, 'FailParts', 'repair_mapping(repair_info_id,fail_parts_id)'),


而站在$failParts實例的角度,則關聯關係變成


'RepairInfos' => array(self::MANY_MANY, 'RepairInfo', 'repair_mapping(fail_parts_id, repair_info_id)'),


#

而前面也已经指出,不需要双方都配置,只需需要的一方设置即可。

之前曾使用过的笨方法:


/*方法一:使用表关系(多对多)*/ 
$fails = $repairInfo->FailParts;//在$repairInfo中使用 
/*方法二:使用原始方法*/ 
$id = $repairInfo->id; 
$maps = RepairMapping::model()->findAll("repair_info_id = $id"); 
$f_ids = array(); 
foreach($maps as $map){ 
array_push($f_ids, $maps[0]->fail_parts_id); 
} 
$f_idsStr = implode(',',$f_ids); 
$fails = FailParts::model()->findAll("id IN ($f_idsStr)");


2,主动加载——with

(1)一对多
(2)多对多


$posts = Post::model()->('author')->findAll();


例子:

User.php


//查询一个机房$idc_id的所有用户 
function getAdminedUsersByIdc($idc_id){ 
$c = new CDbCriteria(); 
$c->join = "JOIN idc_user on t.id=idc_user.user_id"; 
$c->condition = "idc_user.idc_id=$idc_id"; 
return User::model()->with('Idcs')->findAll($c); 
} 
//规则中配置 
'Idcs' => array(self::MANY_MANY, 'Idc', 'idc_user(user_id, idc_id)'),


批注:没有with('Idcs'),执行后的结果也一样。只不过不再是eager loading。

三、带参数的关联配置

常见的条件有

1,condition 按某个表的某个字段加过滤条件

例如:


//在User的model里定义,如下关联关系 
'doingOutsources' => array(self::MANY_MANY, 'Outsource', 'outsource_user(user_id, outsource_id)', 
'condition' => "doingOutsources.status_id IN(" . Status::ASSIGNED . "," . Status::STARTED ."," . Status::REJECTED .")"),


//结论:condition是array里指定model的一个字段。

显然,doingOutsources是真实数据表Outsource的别名,所以在condition中可以使用doingOutsources.status_id,当然也可以使用Outsource.status_id。另本表名user的默认别名是t。

2,order 按某个表的某个字段升序或降序


//在RepairInfo的model里定义,如下关联关系 
'WorkSheet' => array(self::HAS_MANY, 'WorkSheet', 'repair_info_id', order => 'created_at desc'), 
//调用 
$worksheets = $repair_info->WorkSheet; //此时$worksheets是按降序排列


//结论:order是array里指定model的一个字段。

with
joinType
select
params
on
alias
together
group
having
index

还有用于lazy loading的
limit 只取5个或10个
offset
through
官方手册
'posts'=>array(self::HAS_MANY, 'post', 'author_id', 'order'=>'posts.create_time DESC', 'with'=>'categories'),

四、静态查询(仅用于HAS_MANY和MANY_MANY)

关键字:self:STAT

1,基本用法。例如,


class Post extends CActiveRecord 
{ 
...... 

public function relations() 
{ 
return array( 
'commentCount'=>array(self::STAT, 'Comment', 'post_id'), 
'categoryCount'=>array(self::STAT,'Category','post_category(post_id, category_id)'); 

); 
} 
}


2,静态查询也支持上面的各种条件查询


'doingOutsourceCount' => array(self::STAT, 'Outsource', 'outsource_user(user_id, outsource_id)', 
'condition' => "outsource.status_id IN(" . Status::ASSIGNED . "," . Status::STARTED ."," . Status::REJECTED .")"),


其他查询还包括

condition 使用较多

order
select
defaultValue
params
group
having

3,静态查询的加载方式

可以使用lazy loading方式
$post->commentCount.
也可以使用eager loading方式
$posts = Post::model()->with('commentCount','categoryCount')->findAll();
注with中字符串一定是别名。

两者的性能比较:

如果需要取所有post的所有comment,前者需要2N+1次查询,而后者只有一次。两者的选择视情况而定。

相关推荐:

Yii2中的代码自动加载机制

Yii框架中的form表单

Yii2实现增删改查后留在当前页的方法详解

以上是YII關聯查詢詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何防止會話固定攻擊?如何防止會話固定攻擊?Apr 28, 2025 am 12:25 AM

防止會話固定攻擊的有效方法包括:1.在用戶登錄後重新生成會話ID;2.使用安全的會話ID生成算法;3.實施會話超時機制;4.使用HTTPS加密會話數據,這些措施能確保應用在面對會話固定攻擊時堅不可摧。

您如何實施無會話身份驗證?您如何實施無會話身份驗證?Apr 28, 2025 am 12:24 AM

實現無會話身份驗證可以通過使用JSONWebTokens(JWT)來實現,這是一種基於令牌的認證系統,所有的必要信息都存儲在令牌中,無需服務器端會話存儲。 1)使用JWT生成和驗證令牌,2)確保使用HTTPS防止令牌被截獲,3)在客戶端安全存儲令牌,4)在服務器端驗證令牌以防篡改,5)實現令牌撤銷機制,如使用短期訪問令牌和長期刷新令牌。

PHP會議有哪些常見的安全風險?PHP會議有哪些常見的安全風險?Apr 28, 2025 am 12:24 AM

PHP會話的安全風險主要包括會話劫持、會話固定、會話預測和會話中毒。 1.會話劫持可以通過使用HTTPS和保護cookie來防範。 2.會話固定可以通過在用戶登錄前重新生成會話ID來避免。 3.會話預測需要確保會話ID的隨機性和不可預測性。 4.會話中毒可以通過對會話數據進行驗證和過濾來預防。

您如何銷毀PHP會議?您如何銷毀PHP會議?Apr 28, 2025 am 12:16 AM

銷毀PHP會話需要先啟動會話,然後清除數據並銷毀會話文件。 1.使用session_start()啟動會話。 2.用session_unset()清除會話數據。 3.最後用session_destroy()銷毀會話文件,確保數據安全和資源釋放。

如何更改PHP中的默認會話保存路徑?如何更改PHP中的默認會話保存路徑?Apr 28, 2025 am 12:12 AM

如何改變PHP的默認會話保存路徑?可以通過以下步驟實現:在PHP腳本中使用session_save_path('/var/www/sessions');session_start();設置會話保存路徑。在php.ini文件中設置session.save_path="/var/www/sessions"來全局改變會話保存路徑。使用Memcached或Redis存儲會話數據,如ini_set('session.save_handler','memcached');ini_set(

您如何修改PHP會話中存儲的數據?您如何修改PHP會話中存儲的數據?Apr 27, 2025 am 12:23 AM

tomodifyDataNaphPsession,startTheSessionWithSession_start(),然後使用$ _sessionToset,修改,orremovevariables.1)startThesession.2)setthesession.2)使用$ _session.3)setormodifysessessvariables.3)emovervariableswithunset()

舉一個在PHP會話中存儲數組的示例。舉一個在PHP會話中存儲數組的示例。Apr 27, 2025 am 12:20 AM

在PHP會話中可以存儲數組。 1.啟動會話,使用session_start()。 2.創建數組並存儲在$_SESSION中。 3.通過$_SESSION檢索數組。 4.優化會話數據以提升性能。

垃圾收集如何用於PHP會議?垃圾收集如何用於PHP會議?Apr 27, 2025 am 12:19 AM

PHP會話垃圾回收通過概率機制觸發,清理過期會話數據。 1)配置文件中設置觸發概率和會話生命週期;2)可使用cron任務優化高負載應用;3)需平衡垃圾回收頻率與性能,避免數據丟失。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版