Cakephp查询关联表的方法总结

edited 十月 2013 in CakePHP
Note项目的数据结构为例,我们要实现下面的操作:

我们可以采用下列几种方式实现

{查询指定User的Note中包含关键词keyword的所有信息}

1.SQL语句
SELECT * FROM Users AS User
LEFT JOIN Notes AS Note ON User.id = Note.user_id 
WHERE
User.id = {$user_id} 
AND
Note.subject LIKE '%{keyword}%'

然后我们执行这个SQL语句,使用模型的query方法
$data = $this->User->query($sql);

2.使用模型的bindModel()和unbindModel()方法

关于这两种方法的说明,请参照

http://api.cakephp.org/class/model

我们的做法是
//重新绑定关联指定查询条件 
 
$this->User->unbindModel('Note'); 
$this->User->bindModel(
    'hasMany' => array( 
        'Note' => array( 
            'conditions' => array(
                'Note.subject LIKE' => '%'.$keyword.'%'
            )        
        )    
    )
);

//指定主表条件获取数据 
$data = $this->User->find('all',array( 
    'conditions' => array( 
        'User.id' => $user_id
    ) 
)); 

//或者 
 
$data = $this->User->read(null,$user_id);

3. 使用Cakephp的核心行为(Behavior) Containable

我们先建立自己的AppModel类,建立文件/app/app_model.php
class AppModel extends Model { 
    //加载核心行为
    var $actsAs = array('Containable'); 
}

然后我们在控制器中,可以通过这样的代码查询
$this->User->contain('Note.subject LIKE' => '%'.$keyword.'%');

$data = $this->User->find('all',array(
    'conditions' => array(
        'User.id' => $user_id
    )
));

也可以直接写到find语句中,类似下面的
$data = $this->User->find('all',array(
    'conditions' => array(
        'User.id' => $user_id
    ),
    'contain' => array(
        'Note' => array(
            'conditions' => array(
                'Note.subject LIKE' => '%'.$keyword.'%'
            )
        )
    )
));

注意事项:

如果要查询{User.name或者Note.subject包含关键词keyword的所有记录}

此时,Cakephp的find方法无法实现这个查询,必须使用上面介绍的自定义SQL语句,如下:
SELECT *
FROM users AS User
LEFT JOIN notes AS Note ON User.id = Note.user_id
WHERE
User.name LIKE '%keyword%'
OR
Note.subject LIKE '%keyword%'



David 的文章 CakePHP从两个模型中获取数据!

原始討論: http://twpug.net/x/modules/newbb/viewtopic.php?topic_id=4158

評論

  • edited 五月 2009
    SELECT *
    FROM users AS User
    LEFT JOIN notes AS Note ON User.id = Note.user_id
    WHERE
    User.name LIKE '%keyword%'
    OR
    Note.subject LIKE '%keyword%'
    

    也許可以轉為
    $data = $this->User->find('all',array(
        'conditions' => array(
            'OR' => array(
                'User.name LIKE' => '\'%keyword%\'',
                'Note.subject LIKE' => '\'%keyword%\'',
            ),
        ),
        'joins' => array(
            array(
                'table' => 'notes',
                'alias' => 'Note',
                'type' => 'LEFT',
                'conditions'=> array('User.id = Note.user_id'),
            ),        
        )
    ));
    

    不過沒有真的試過,需要印證一下 ;)

    只是有時候還是透過 SQL 做複雜的查詢比較直覺
  • edited 五月 2009
    谢谢Kiang!
    您提供的方法已经通过验证!
    以下是我们测试成功后的完整代码!
    contorller:
    $results = $this->User->find('all',array(
    			    'conditions' => array(
    			        'OR' => array(
    			            'User.name LIKE' => '%'.$this->data['User']['q'].'%',
    			            'Note.subject LIKE' => '%'.$this->data['User']['q'].'%',
    			        ),
    			    ),
    			    'joins' => array(
    			        array(
    			            'table' => 'notes',
    			            'alias' => 'Note',
    			            'type' => 'LEFT',
    			            'conditions'=> array('User.id = Note.user_id'),
    			        ),
    			    ),
    			    'fields' => array(
    			    	'User.name',
    			    	'Note.subject',
    			    	'Note.created'
    			    )
    			));
    			$this->set('results',$results);
    
    views:
    <?php if(isset($results)){?>
      <?php foreach($results as $resu): ?>
      <tr>
      	<td><?php echo $resu['User']['name'] ?></td>
      	<td><?php echo $resu['Note']['subject'] ?></td>
      	<td><?php echo $resu['Note']['created'] ?></td>
      </tr>
      <?php endforeach;?>
      <?php } ?>
    
Sign In or Register to comment.