【问题标题】:CakePHP order query results on more than 1 levelCakePHP 1 级以上的订单查询结果
【发布时间】:2011-01-06 09:20:04
【问题描述】:

我使用 Containable 行为来获取评论列表(belongsTo Post,属于 Question;Question hasMany Post,Post hasMany Comments;所有这些都属于 Users)。

$data = $this->Question->find ( 'first', 
    array ('contain' => 
        array ('User', 
               'Post' => array ('User', /* 'order' => 'User.created DESC'*/ )
        ) 
    ) 
);

当我注释掉上面 cmets 中的部分时,它起作用了。我想这是可以预料的,但我想要的是所有找到的帖子,应该按照它们所属的“用户”的“创建”字段的顺序进行排序。如何在 CakePHP 中完成这种更深层次的排序?我总是得到,“警告(512):SQL 错误:1054:'order 子句'中的未知列 'User.created'”

感谢您的帮助!

【问题讨论】:

    标签: php cakephp containable


    【解决方案1】:

    此外,您可能会尝试通过不使用联接的查找调用对相关表进行分组。

    将您的调试级别设置为大于 1 的值,以便您可以查看查询日志并确保 Cake 没有执行两次查询来获取您的数据。如果是这种情况,那么第一个查询实际上并没有引用第二个表。

    如果您想在这些情况下手动强制加入,可以使用 Nate 在以下链接中概述的 Ad-Hoc 加入方法。

    http://bakery.cakephp.org/articles/view/quick-tip-doing-ad-hoc-joins-in-model-find

    【讨论】:

    • 我查看了调试输出,你是对的,它没有执行JOIN。这很不幸,真的没有其他方法可以让 CakePHP 做到吗?
    • teknoid.wordpress.com/2008/07/17/forcing-an-sql-join-in-cakephp teknoid 提供了一个解决方法,说明如何通过取消绑定 hasMany 并将其替换为使用连接的临时 hasOne 来强制左连接。阅读它并让我知道这是否适合您,否则我可以发布临时加入代码供您查看。
    • 很高兴能提供帮助,但有时很难找到适合 CakePHP 的内容。那里有大量陈旧过时的信息,有时好东西被埋没了。
    【解决方案2】:

    我找到了两种方法来解决这个问题。 第一种是直接在模型中定义二级关联。 现在,您将可以在任何地方访问这些数据。 它应该看起来像这样.....

    var $belongsTo = array(
    'Foo' => array(
      'className' => 'Foo', //unique name of 1st level join ( Model Name )
      'foreignKey' => 'foo_id', //key to use for join
      'conditions' => '',
      'fields' => '',
      'order' => ''
    ),
    'Bar' => array(
      'className' => 'Bar', //name of 2nd level join ( Model Name )
      'foreignKey' => false,
      'conditions' => array(
        'Bar.id = Foo.bar_id' //id of 2nd lvl table = associated column in 1st level join
      ),
      'fields' => '',
      'order' => ''
    )
    );
    

    这种方法的问题在于,它会使一般查询变得比需要的更复杂。 因此,您还可以将二级查询直接添加到 te find 或 paginate 语句中,如下所示:(注意:我发现由于某种原因,您不能在二级连接中使用 $belongsTo 关联,如果它们需要重新定义它们已定义。例如,如果“Foo”已在 $belongsTo 中定义,则需要创建一个重复的“Foo1”以使关联生效,如下例所示。)

    $options['joins'] = array(
    
    array('table' => 'foos',
      'alias' => 'Foo1',
      'type' => 'inner',
      'conditions' => array(
        'CurrentModel.foo_id = Foo1.id'
      )
    ),
    array('table' => 'bars',
      'alias' => 'Bar',
      'type' => 'inner',
      'foreignKey' => false,
      'conditions' => array(
        'Bar.id = Foo1.bar_id'
      )
    )
    );
    
    $options['conditions'] = array('Bar.column' => "value");
    $this->paginate = $options;
    $[modelname] = $this->paginate();
    $this->set(compact('[modelname]'));
    

    我希望这足够清楚,可以理解并且对某人有所帮助。

    【讨论】:

      【解决方案3】:

      检查您的递归值。如果限制太多,它将忽略可包含的链接,IIRC。我记得有几次碰到这个。我会尝试包含多个模型,但我的 recursive 选项设置为 0 并且什么都不会被拉动。对于您的示例,我认为 1 (默认值)的值就足够了,但也许您已将其明确设置为 0 某处?

      【讨论】:

      • 我实际上将递归选项排除在外,因为我相信 Containable 会为您选择最合适的选项(如果您指定它,事情只会变得更糟)。
      • 这不是我的经验。已经有一段时间了,但我隐约记得有一次失去了几个小时,因为我假设了同样的事情。可能是我的记忆在这一点上不准确。
      【解决方案4】:

      您可以在调用 find() 之前添加以下内容:

       $this->Question->order = 'Question.created DESC';
      

      【讨论】:

      • 这将按其created 字段对问题进行排序,这不是我想要的。也许你的意思是$this->Question->Post->order = 'User.created DESC';
      • 无论如何,我尝试了 purohit 的示例,但它似乎不起作用。也许它在模型的不同实例上设置排序顺序,而不是 Question 模型实际使用的......?
      【解决方案5】:

      是的,我不知道如何根据相关/关联模型进行排序,所以最终使用了Set::sort() 方法。结帐this article 以获得很好的解释。

      // This finds all FAQ articles sorted by:
      // Category.sortorder, then Category.id, then Faq.displaying_order
      $faqs = $this->Faq->find('all', array('order' => 'displaying_order'));
      $faqs = Set::sort($faqs, '{n}.Category.id', 'ASC');
      $faqs = Set::sort($faqs, '{n}.Category.sortorder', 'ASC');
      

      ...是的,它可能应该是 Category->find(),但不幸的是,最初的开发人员并没有这样编码,我不想修改视图。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-13
        • 2011-11-30
        • 1970-01-01
        • 2021-02-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多