關係實際上就是關係模型在某一時刻的狀態或內容。也就是說,關係模式是型,關係是它的值。關係模式是靜態的、穩定的,而關係是動態的、隨時間不斷變化的,因為關係操作在不斷地更新著資料庫中的數據。
基本介紹
- 中文名:關聯模型
- 外文名:Association Model
- 套用領域:計算機等
- 涉及軟體:ThinkPHP
- 關聯關係:一對一、一對多、多對多
- 套用對象:數據表
簡介
- 一對一關聯 :ONE_TO_ONE,包括HAS_ONE 和 BELONGS_TO
- 一對多關聯 :ONE_TO_MANY,包括HAS_MANY 和 BELONGS_TO
- 多對多關聯 :MANY_TO_MANY
- 有一個員工檔案管理系統項目,這個項目要包括下面的一些數據表:基本信息表、員工檔案表、部門表、項目組表、銀行卡表(用來記錄員工的銀行卡資料)。
- 這些數據表之間存在一定的關聯關係,我們以員工基本信息表為參照來分析和其他表之間的關聯:
- 每個員工必然有對應的員工檔案資料,所以屬於HAS_ONE關聯;
- 每個員工必須屬於某個部門,所以屬於BELONGS_TO關聯;
- 每個員工可以有多個銀行卡,但是每張銀行卡只可能屬於一個員工,因此屬於HAS_MANY關聯;
- 每個員工可以同時在多個項目組,每個項目組同時有多個員工,因此屬於MANY_TO_MANY關聯;
- 分析清楚數據表之前的關聯關係後,我們才可以進行關聯定義和關聯操作。
關聯定義
關聯定義的格式
namespace Home\Model; use Think\Model\RelationModel; class UserModel extends RelationModel{ protected $_link = array( '關聯1' => array( '關聯屬性1' => '定義', '關聯屬性N' => '定義', ), '關聯2' => array( '關聯屬性1' => '定義', '關聯屬性N' => '定義', ), '關聯3' => HAS_ONE, // 快捷定義 ... ); } |
HAS_ONE
namespace Home\Model; use Think\Model\RelationModel; class UserModel extends RelationModel{ protected $_link = array( 'Profile'=> self::HAS_ONE, ); } |
namespace Home\Model; use Think\Model\RelationModel; class UserModel extends RelationModel{ protected $_link = array( 'Profile'=>array( 'mapping_type' => self::HAS_ONE, 'class_name' => 'Profile', // 定義更多的關聯屬性 …… ), ); } |
- mapping_type :關聯類型
這個在HAS_ONE 關聯裡面必須使用HAS_ONE 常量定義。 - class_name :要關聯的模型類名
例如,class_name 定義為Profile的話則表示和另外的Profile模型類關聯,這個Profile模型類是無需定義的,系統會自動定位到相關的數據表進行關聯。 - mapping_name :關聯的映射名稱,用於獲取數據用
該名稱不要和當前模型的欄位有重複,否則會導致關聯數據獲取的衝突。如果mapping_name沒有定義的話,會取class_name的定義作為mapping_name。如果class_name也沒有定義,則以數組的索引作為mapping_name。 - foreign_key : 關聯的外鍵名稱
外鍵的默認規則是當前數據對象名稱_id,例如: UserModel對應的可能是表think_user (注意:think只是一個表前綴,可以隨意配置) 那么think_user表的外鍵默認為 user_id,如果不是,就必須在定義關聯的時候顯式定義 foreign_key 。 - mapping_fields : 關聯要查詢的欄位
默認情況下,關聯查詢的關聯數據是關聯表的全部欄位,如果只是需要查詢個別欄位,可以定義關聯mapping_fields屬性。 - as_fields :直接把關聯的欄位值映射成數據對象中的某個欄位
這個特性是ONE_TO_ONE 關聯特有的,可以直接把關聯數據映射到數據對象中,而不是作為一個關聯數據。當關聯數據的欄位名和當前數據對象的欄位名稱有衝突時,還可以使用映射定義。
BELONGS_TO
'Dept' => array( 'mapping_type' => self::BELONGS_TO, 'class_name' => 'Dept', 'foreign_key' => 'userId', 'mapping_name' => 'dept', // 定義更多的關聯屬性 …… ), |
屬性 | 描述 |
---|---|
class_name | 要關聯的模型類名 |
mapping_name | 關聯的映射名稱,用於獲取數據用 該名稱不要和當前模型的欄位有重複,否則會導致關聯數據獲取的衝突。 |
foreign_key | 關聯的外鍵名稱 |
mapping_fields | 關聯要查詢的欄位 |
condition | 關聯條件 |
parent_key | 自引用關聯的關聯欄位 默認為parent_id 自引用關聯是一種比較特殊的關聯,也就是關聯表就是當前表。 |
as_fields | 直接把關聯的欄位值映射成數據對象中的某個欄位 |
HAS_MANY
'Article' => array( 'mapping_type' => self::HAS_MANY, 'class_name' => 'Article', 'foreign_key' => 'userId', 'mapping_name' => 'articles', 'mapping_order' => 'create_time desc', // 定義更多的關聯屬性 …… ), |
屬性 | 描述 |
---|---|
class_name | 要關聯的模型類名 |
mapping_name | 關聯的映射名稱,用於獲取數據用 該名稱不要和當前模型的欄位有重複,否則會導致關聯數據獲取的衝突。 |
foreign_key | 關聯的外鍵名稱 |
parent_key | 自引用關聯的關聯欄位 默認為parent_id |
condition | 關聯條件 關聯查詢的時候會自動帶上外鍵的值,如果有額外的查詢條件,可以通過定義關聯的condition屬性。 |
mapping_fields | 關聯要查詢的欄位 默認情況下,關聯查詢的關聯數據是關聯表的全部欄位,如果只是需要查詢個別欄位,可以定義關聯的mapping_fields屬性。 |
mapping_limit | 關聯要返回的記錄數目 |
mapping_order | 關聯查詢的排序 |
MANY_TO_MANY
'Group' => array( 'mapping_type' => self::MANY_TO_MANY, 'class_name' => 'Group', 'mapping_name' => 'groups', 'foreign_key' => 'userId', 'relation_foreign_key' => 'groupId', 'relation_table' => 'think_group_user' //此處應顯式定義中間表名稱,且不能使用C函式讀取表前綴 ) |
屬性 | 描述 |
---|---|
class_name | 要關聯的模型類名 |
mapping_name | 關聯的映射名稱,用於獲取數據用 該名稱不要和當前模型的欄位有重複,否則會導致關聯數據獲取的衝突。 |
foreign_key | 關聯的外鍵名稱 外鍵的默認規則是當前數據對象名稱_id |
relation_foreign_key | 關聯表的外鍵名稱 默認的關聯表的外鍵名稱是表名_id |
mapping_limit | 關聯要返回的記錄數目 |
mapping_order | 關聯查詢的排序 |
relation_table | 多對多的中間關聯表名稱 |
查詢
array( 'id' => 1, 'account' => 'ThinkPHP', 'password' => '123456', 'Profile' => array( 'email' => '[email protected]', 'nickname' => '流年', ), ) |
- 'as_fields' => 'email,nickname:username',
表示關聯表的nickname欄位映射成當前數據對象的username欄位。
默認會把所有定義的關聯數據都查詢出來,有時候我們並不希望這樣,就可以給relation方法傳入參數來控制要關聯查詢的。 - $User = D("User");$user = $User->relation('Profile')->find(1);
關聯查詢一樣可以支持select方法,如果要查詢多個數據,並同時獲取相應的關聯數據,可以改成: - $User = D("User");$list = $User->relation(true)->Select();
如果希望在完成的查詢基礎之上 再進行關聯數據的查詢,可以使用 - $User = D("User");$user = $User->find(1);// 表示對當前查詢的數據對象進行關聯數據獲取$profile = $User->relationGet("Profile");
事實上,除了當前的參考模型User外,其他的關聯模型是不需要創建的。
關聯操作
- 每個用戶有一個檔案表是HAS_ONE關聯;
- 每個用戶屬於一個部門是BELONGS_TO關聯;
- 每個用戶有多張銀行卡是HAS_MANY關聯;
- 每個用戶可能屬於多個項目組,每個項目組也有多個用戶是MANY_TO_MANY關聯。
創建數據表
- // 部門表
- // 用戶表
- // 用戶檔案表
- // 銀行卡表
- // 項目組表
- // 用戶-項目組
- 表
關聯定義
[php]view plaincopyprint? classUserModelextendsModel { protected$_link=array( ‘Profile’=>array( ‘mapping_type’=>HAS_ONE, ‘mapping_name’=>’Profile’, ‘class_name’=>’Profile’, ‘foreign_key’=>’user_id’, ), ‘Dept’=>array( ‘mapping_type’=>BELONGS_TO, ‘mapping_name’=>’Dept’, ‘class_name’=>’Dept’, ‘foreign_key’=>’dept_id’, ), ‘Card’=>array( ‘mapping_type’=>HAS_MANY, ‘mapping_name’=>’Card’, ‘class_name’=>’Card’, ‘foreign_key’=>’user_id’, ), ‘Group’=>array( ‘mapping_type’=>MANY_TO_MANY, ‘mapping_name’=>’Group’, ‘class_name’=>’Group’, ‘foreign_key’=>’user_id’, ‘relation_foreign_key’=>’group_id’, ‘relation_table’=>’think_user_group’, ), ); } |
- class ProfileModel extends Model {}
- class DeptModel extends Model {}
- class CardModel extends Model {}
- class GroupModel extends Model {}
關聯寫入
[php]view plaincopyprint? $User=D(”User”); $User->name=‘thinkphp’; $User->dept_id=1; $User->Profile=array( ‘email’=>’[email protected]’, ‘nickname’=>’流年’, ); $User->Card=array( array(‘id’=>1.’card’=>’12345678′), array(‘id’=>2,’card’=>’88888888′), ); $User->Group=array( array(’id’=>1), array(’id’=>2), ); $User->add(”,true); |
- $User->add();
方法即可同時進行關聯寫入。
為了驗證關聯數據是否已經寫入,我們現在來使用關聯查詢把相關的數據查出來。 - $user = $User->relation(true)->find(1);
Dump($user);
可以看到輸出的結果,把User模型關聯的數據都顯示出來了。如果我們只希望獲取某個關聯數據,可以使用 - $user = $User->relation(‘Profile’)->find(1);
表示只是獲取關聯的用戶檔案數據。
數據集的查詢也可以支持關聯查詢,使用 - $user = $User->relation(true)->findAll();
能夠顯示出完整的含有關聯數據的數據集。
更新關聯數據
[php]view plaincopyprint? $user[‘id’]=1; $user['name']=‘tp’; $user['Profile']['email']=‘[email protected]’; $user['Card']=array( array(’id’=>1,’card’=>’66666666′), array(’id’=>2,’card’=>’77777777′), ); $user[‘Group’]=array( array(’id’=>1), array(’id’=>3), ); $User->save($user,’id=1′,true); |