不可否认Cakephp对于查询的封装是有限制的,但是通过利用Cakephp的语法规则,可以很好的弥补这一点。

我们在应用中遇到的问题:

{查询Note的ID小于10的所有User,User表和Note表是一对多关联}

我们通常的做法是

1. $users = $this->User->find('all',array(
2. 'conditions' => array(
3. 'Note.id <' => 10
4. )
5. ));

注意:这种做法是错误的。

原因是:

Cakephp对于hasMany的关联,会生成下列的语句

1. SELECT `User`.`id`, `User`.`name`, `User`.`username`, `User`.`password`, `User`.`created` FROM `users` AS `User` WHERE `Note`.`id` < 10

可以看到,Note表并没有被Join到查询中,所以,MySql会提示

1. Unknown column 'Note.id' in 'where clause'

我们应该怎样查询条件从属于关联表的记录呢?

简单介绍一下Cakephp的四种关联模式对应的从属关联条件的方法。

1. 最简单的hasOne和belongsTo关联

这类的关联我们可以直接写关联表的条件,而不会出现Unknow column的错误。

2. 稍稍复杂的hasMany关联(一对多关联)

就像你在上面看见的,hasMany关联是不能直接实现上述的查询条件的,但是我们可以变通一下,我们可以把hasMany关联查询转换为belongsTo关联查询,按照上面的条件,我们再试一试

01. $users = $this->User->Note->find('all',array(
02. 'conditions' => array(
03. 'Note.id <' => 10
04. ),
05. 'contain' => array('User'),
06. 'fields' => array(
07. 'Note.id',
08. 'User.id',
09. 'User.name'
10. )
11. ));

这次得到的结果类似于下面的数据

01. Array
02. (
03. [0] => Array
04. (
05. [Note] => Array
06. (
07. [id] => 1
08. )
09. [User] => Array
10. (
11. [id] => 54
12. [name] => Cole Cox
13. )
14. )
15. [1] => Array
16. (
17. [Note] => Array
18. (
19. [id] => 2
20. )
21. [User] => Array
22. (
23. [id] => 81
24. [name] => Vincent Cobb
25. )
26. )
27. )

OK,这就是我们想要的!

同样的方法还可以{查找一个User的所有Friend},请看下面的部分。。。

3. 不太好理解的hasAndBelongsToMany关联(多对多关联)

我们的数据表结构如下

01. --用户表
02.  
03. CREATE TABLE IF NOT EXISTS `users` (
04. `id` int(11) NOT NULL auto_increment,
05. `name` varchar(60) collate utf8_unicode_ci NOT NULL,
06. `username` varchar(20) collate utf8_unicode_ci NOT NULL,
07. `password` varchar(255) collate utf8_unicode_ci NOT NULL,
08. `created` datetime NOT NULL,
09. PRIMARY KEY  (`id`)
10. ) ENGINE=MyISAM;
11.  
12. --用户和好友关联表
13.  
14. CREATE TABLE IF NOT EXISTS `friends_users` (
15. `id` bigint(10) NOT NULL auto_increment,
16. `user_id` bigint(10) NOT NULL,
17. `friend_id` bigint(10) NOT NULL,
18. PRIMARY KEY  (`id`)
19. ) ENGINE=MyISAM;

我们需要建立三个模型类

User模型,对应于users表,文件/app/models/user.php

1. class User extends AppModel{
2. var $name = 'User';
3.  
4. var $hasAndBelongsToMany = array(
5. 'Friend' => array('with' => 'FriendsUser')
6. );
7.  
8. }

Friend模型,也对应users表(Friend和User共享数据),用来和users模型进行多对多关联

文件/app/models/friend.php

1. class Friend extends AppModel {
2. var $name = 'Friend';
3. var $useTable = 'users';
4. var $hasAndBelongsTo = array(
5. 'User' => array('with' => 'FriendsUser')
6. );
7. }

FriendsUser模型,对应关联表friends_users,文件/app/models/friends_user.php

1. class FriendsUser extends AppModel {
2. var $name = 'FriendsUser';
3. var $belongsTo = array('Friend','User');
4. }

好了,定义好模型,我们要查询User的所有Friend,在控制器中,要这样

01. class UsersController extends AppController {
02. var $name = 'Users';
03.  
04. //这里,我们要引入这三个模型,如果你有更多的模型,可以一起引入
05. var $uses = array('User','Friend','FriendsUser');
06.  
07. function test(){
08. $conditions = array(
09. 'User.id' => 1
10. );
11. $contain = array('User','Friend');
12. $fields = array(
13. 'User.id',
14. 'User.name',
15. 'Friend.id',
16. 'Friend.name'
17. );
18. $limit = 5;
19.  
20. //我们使用了中间表FriendsUser,来查询,compact函数是cakephp提倡的用法
21. $data = $this->FriendsUser->find('all',compact(
22. 'conditions',
23. 'contain',
24. 'fields',
25. 'limit'
26. ));
27.  
28. debug($data);
29. exit;
30. }
31. }

查询的结果,可能类似下面的数据

01. Array
02. (
03. [0] => Array
04. (
05. [User] => Array
06. (
07. [id] => 1
08. [name] => Drake Duran
09. )
10.  
11. [Friend] => Array
12. (
13. [id] => 2
14. [name] => Dane Knowles
15. )
16.  
17. )
18.  
19. [1] => Array
20. (
21. [User] => Array
22. (
23. [id] => 1
24. [name] => Drake Duran
25. )
26.  
27. [Friend] => Array
28. (
29. [id] => 3
30. [name] => Felix Kelley
31. )
32.  
33. )
34.  
35. )

 

可以看到,这正是我们需要的数据。

总结一下

Cakephp关联表的从表查询,可以借助belongsTo关联来查询,只要我们做好模型的相互关联,查询是没有问题的!