一个无论多么复杂的程序,拆开看无非是三种逻辑结构的组合:顺序结构、条件结构和循环结构。
类似的,数据库中表与表的之间的关联无外乎四种:一对一、一对多、多对一和多对多。
CakePHP的模型层中定义了四种关联模型分别来表示上面的四种关系,他们是hasOne、hasMany、belongsTo和hasAndBelongsToMany。
下面根据代码及生成SQL语句来了解这几种关联模型的用法。
hasOne
假设一条User表的记录对应一条UserSocialInformation表中的记录。
此时UserSocialInformation表中必须要有与User表关联的字段,作为User表的外键。即被关联的模型包含外键
命名格式可以是关联的表名+'_id',如user_id。这种格式。
class User extends AppModel {
var $hasOne = 'UserSocialInformation';
}
查询User表中的首条记录:$this->User->find('first');
生成的SQL
SELECT
`User`.`id`, `User`.`created`, `User`.`modified`, `User`.`agent_id`, `User`.`first_name`, `User`.`last_name`,
`UserSocialInformation`.`id`, `UserSocialInformation`.`user_id` FROM `users` AS `User`
LEFT JOIN `user_social_informations` AS `UserSocialInformation` ON (`UserSocialInformation`.`user_id` = `User`.`id`)
WHERE 1 = 1 LIMIT 1
注意ON (`UserSocialInformation`.`user_id` = `User`.`id`),两者的关联就靠他了。
belongTo
与hasOne类似,若我们想通过UserSocialInformation表查询时同时也把User表的信息查出来,此时必须当前模型包含外键。
class UserSocialInformation extends AppModel {
var $name = 'UserSocialInformation';
var $belongsTo = array('User');
}
通过UserSocialInformation查询:$this->UserSocialInformation->find();
生成的SQL
SELECT
`UserSocialInformation`.`id`,`UserSocialInformation`.`user_id` ,
`User`.`id`, `User`.`created`, `User`.`modified`, `User`.`agent_id`, `User`.`group_id`
FROM `user_social_informations` AS `UserSocialInformation`
LEFT JOIN `users` AS `User` ON (`UserSocialInformation`.`user_id` = `User`.`id`)
WHERE 1 = 1 LIMIT 1
延伸
一个用户属于某一个组(group)同时属于某一个代理商(agent),意味着user表中要有对应group表和agent表的外键,为了规范,最好命名为group_id和agent_id,这样CakePHP会自动关联。
class User extends AppModel {
var $name = 'User';
var $belongsTo = array('Group', 'Agent');
}
查询时生成的大概SQL(省去了多余的表字段)
SELECT `User`.`id`, `User`.`created`, `User`.`modified`, `User`.`agent_id`, `User`.`group_id`, `User`.`username`, `User`.`password`,
`Group`.`id`, `Group`.`parent_id`, `Group`.`name`,
`Agent`.`id`, `Agent`.`affiliate_id`, `Agent`.`agency_name`
FROM `users` AS `User`
LEFT JOIN `groups` AS `Group` ON (`User`.`group_id` = `Group`.`id`)
LEFT JOIN `agents` AS `Agent` ON (`User`.`agent_id` = `Agent`.`id`) WHERE 1 = 1 LIMIT 1
hasMany
打开一篇文章可能有属于该文章的多条评论,他们是一对多的关系。我们可以在文章表和留言表之间建立关联,留言表中保存文章表的主键。即其他模型包含外键
这样就可以把一篇文章的记录和属于该文章的评论全部提取出来。
类似的以一条房屋表Property记录包含多条房屋图片(PropertyImage)记录为例。
Property的模型文件
class Property extends AppModel {
var $name = 'Property';
public $hasMany = array('PropertyImages'=>array('order'=>'PropertyImages.is_deleted, PropertyImages.order_image ASC'));
}
PropertyImage的模型文件
class PropertyImage extends AppModel {
var $name = 'PropertyImage';
}
查询指定ID的房屋记录
$result = $this->Property->findById('cec390de-75dd-4544-351c-f34a408e6f51');
CakePHP会自动进行两条查询语句
SELECT `Property`.`id`, `Property`.`modified`,`Property`. ......
FROM `properties` AS `Property`
WHERE `Property`.`id` = 'cec390de-75dd-4544-351c-f34a408e6f51' LIMIT 1
SELECT `PropertyImages`.`id`, `PropertyImages`.`property_id`, `PropertyImages`.`image_name`......
FROM `property_images` AS `PropertyImages`
WHERE `PropertyImages`.`property_id` = ('cec390de-75dd-4544-351c-f34a408e6f51')
ORDER BY `PropertyImages`.`is_deleted` ASC, `PropertyImages`.`order_image`
生成的结果是个数组,结构类似:
Array
(
[Property] => Array
(
[id] => cec390de-75dd-4544-351c-f34a408e6f51
[modified] => 2013-10-28 16:40:15
)
[PropertyImages] => Array
(
[0] => Array
(
[id] => 3ee846ec-e378-e014-8196-a5acdb8dcb32
[property_id] => cec390de-75dd-4544-351c-f34a408e6f51
[image_name] => 1330043177_20111118174028.jpg
)
[1] => Array
(
[id] => 3ebf5363-580a-50c4-b55d-c11b0f958876
[property_id] => cec390de-75dd-4544-351c-f34a408e6f51
[image_name] => 1330043177_201111161100362.jpg
)
[2] => Array
(
[id] => 9c34181f-f2fd-6d84-25cd-23583535e218
[property_id] => cec390de-75dd-4544-351c-f34a408e6f51
[image_name] => 1330043178_201111181740281.jpg
)
[3] => Array
(
[id] => 94d817a4-5bb0-ae94-adbc-0749f63c4cff
[property_id] => cec390de-75dd-4544-351c-f34a408e6f51
[image_name] => 1330043175_1_Orana_St.jpg
)
这种结构结果使用起来非常方便。