【问题标题】:How to select a specific field additionally to a tables default fields?除了表格默认字段外,如何选择特定字段?
【发布时间】:2015-04-14 22:49:41
【问题描述】:

我希望使用 JOIN 从 CakePHP 中的表和视图中选择数据,如下所示:

$this->Annonces->find('all')
        ->where($arrFiltres)
        ->order($arrOrder)
        ->join([
            'table' => 'annonces_suivis',
            'alias' => 'AnnoncesSuivis',
            'conditions' => [...],      
        ]);

并且希望能够像这样从第一个表和联合表的 som 中选择所有字段:

->select(['Annonces.*', 'AnnoncesSuivis.id']);

但这会创建一个错误的 SQL 查询。

【问题讨论】:

    标签: cakephp cakephp-3.0 query-builder


    【解决方案1】:

    .* 不受 ORM 查询支持,它会将其转换为

    Annonces.* AS Annonces__*
    

    这是无效的 SQL。它适用于较低级别的数据库查询 (Connection::newQuery()),它不会添加别名,但不会返回实体,因此这可能不是您想要的。

    Cookbook > Database Access & ORM > Database Basics > \Cake\Database\Connection::newQuery()

    传递一个表格对象

    从 CakePHP 3.1 开始,您可以将表格对象传递给 Query::select(),这将导致表格的所有字段都被选中。

    $this->Annonces
        ->find('all')
        ->select(['AnnoncesSuivis.id'])
        ->select($this->Annonces)
        ->join([
            'table' => 'annonces_suivis',
            'alias' => 'AnnoncesSuivis',
            'conditions' => [ /* ... */ ],     
        ])
        ->where($arrFiltres)
        ->order($arrOrder);
    

    这样AnnoncesSuivis.id字段和Annonces的所有字段都会被选中。

    Cookbook > Database Access & ORM > Query Builder > Selecting All Fields From a Table

    从架构构建字段

    这也是在内部传递一个表对象会导致的,CakePHP

    $query = $this->Annonces->find('all');
    
    $fields = $query->aliasFields(
        $this->Annonces->schema()->columns(),
        $this->Annonces->alias()
    );
    
    $query
        ->select(array_merge(['AnnoncesSuivis.id'], $fields))
        ->join([
            'table' => 'annonces_suivis',
            'alias' => 'AnnoncesSuivis',
            'conditions' => [ /* ... */ ],     
        ])
        ->where($arrFiltres)
        ->order($arrOrder);
    

    这也适用于可以传递给Table::find()fields 选项,但在这种情况下您必须使用单独的查询对象,例如

    $fields = $this->Annonces->query()->aliasFields(
        $this->Annonces->schema()->columns(),
        $this->Annonces->alias()
    );
    
    $this->Annonces->find('all', [
        'fields' => array_merge(['AnnoncesSuivis.id'], $fields)
        // ...
    ]);
    

    使用Query::autoFields()

    在早期的 CakePHP 版本中,您还可以使用 Query::autoFields(),当设置为 true 时,将自动包含主表的字段和可能的包含。

    Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Passing Conditions to Contain

    在您通过Query::select() 设置字段之前,自动选择所有字段是默认行为,在这种情况下,您必须明确启用Query::autoFields()

    $this->Annonces
        ->find('all')
        ->select(['AnnoncesSuivis.id'])
        ->autoFields(true)
        ->join([
            'table' => 'annonces_suivis',
            'alias' => 'AnnoncesSuivis',
            'conditions' => [ /* ... */ ],     
        ])
        ->where($arrFiltres)
        ->order($arrOrder);
    

    这应该会为您提供所需的查询,但是如上所述,这仅适用于主表和容器,如果您想包含手动连接表的所有字段,那么您必须通过以下方式指定它们一个。

    【讨论】:

    • 非常感谢。我会把它放在我们的生产版本中:)
    • 就我而言,我必须加入这么多表,并且还需要所有表中的几乎所有字段。指定所有字段并不是一个好的解决方案。有没有办法使用 * 或其他东西一次全选?
    • @Dashrath 正如我所说,这里目前无法将* 与 ORM 查询构建器一起使用。如果您需要几乎 all,那么只需让ORM 选择all,根本不手动指定任何字段。另请参阅 github.com/cakephp/cakephp/issues/6904
    • 当我使用 ->select() 时没有传入任何参数,cakephp3 只返回基表列,而不是所有连接表的所有列。
    • @Dashrath 这就是我所描述的行为。您将不得不使用 containments 而不是手动连接。
    【解决方案2】:

    您也可以在实体中创建虚拟字段:

    namespace App\Model\Entity;
    use Cake\ORM\Entity;
    
    class User extends Entity { 
        protected function _getFullName() {
           return $this->_properties['first_name'] . ' ' . $this->_properties['last_name']; 
        } 
    }
    

    echo $entity->full_name;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-06
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 2021-12-11
      • 2014-04-11
      • 2019-07-26
      • 1970-01-01
      相关资源
      最近更新 更多