【问题标题】:Multi level ordering in cakePHPcakePHP中的多级排序
【发布时间】:2013-03-13 16:50:44
【问题描述】:

为什么 cakePHP 不将我的所有关联都包含在一个 SQL 查询中?我能够做到这一点的唯一方法是使用“加入”,但我希望 belongsTo 和 Containable 行为就足够了。

这是一个例子: Post->belongsTo->Category->belongsTo->category_type (所有模型均已正确设置并正常工作。

在索引中列出带有分页的帖子,我试试这个:

public function index() {   
    $this->paginate = array( 'contain' => array('Category' => array('CategoryType')));
    $this->set('posts', $this->paginate());
}

这会正确地获取数组,但它在许多 SQL 中都是这样的:

SELECT `Post`.`id`, `Post`.`name`, `Post`.`content`, `Post`.`category_id`, `Category`.`id`, `Category`.`name`, `Category`.`category_type_id` FROM `unit_app`.`post` AS `Post` LEFT JOIN `unit_app`.`categories` AS `Category` ON (`Post`.`category_id` = `Category`.`id`) WHERE 1 = 1 LIMIT 20
SELECT `CategoryType`.`id`, `CategoryType`.`name` FROM `unit_app`.`category_types` AS `CategoryType` WHERE `CategoryType`.`id` = 1
SELECT `CategoryType`.`id`, `CategoryType`.`name` FROM `unit_app`.`category_types` AS `CategoryType` WHERE `CategoryType`.`id` = 2
SELECT `CategoryType`.`id`, `CategoryType`.`name` FROM `unit_app`.`category_types` AS `CategoryType` WHERE `CategoryType`.`id` = 2

这使得在 CategoryType.name ASC 上对该查询进行排序变得困难。 有什么建议吗?

如果连接是唯一的选择,我是否必须在查询之前取消绑定模型? 分页可以与连接一起正常工作吗?

注意!这只是所有模型的一小部分,生成的 post->index 还需要通过类似的关联获取许多其他模型。

(在 cake 2.2.0 和 v2.4.0-dev、php v5.4.11 上测试)

更新! ---------

我只是想展示我的发现。我现在已经在没有连接的情况下解决了这个问题,但我必须在模型中重新绑定才能使其正常工作。

这基本上是我为使其工作所做的工作(也包括分页和排序): 在 Post 模型中: 添加绑定功能:

  $this->unbindModel(array(
    'belongsTo' => array('Category')
  ));

  $this->bindModel(array(
    'hasOne' => array(
      'Category' => array(
        'foreignKey' => false,
        'conditions' => array('Category.id = Post.category_id')
    ),
    'CategoryType' => array(
      'foreignKey' => false,
      'conditions' => array('CategoryType.id = Category.category_type_id')
    ))));

然后我将其添加到 Post 控制器中的索引中:

  $this->Post->bindCategory();
  $this->paginate = array('contain' => array('Category' ,'CategoryType'));
  $this->set('posts', $this->paginate());

我也包含表格标题,仅用于文档:

<th><?php echo $this->Paginator->sort('CategoryType.name', 'Type'); ?></th>
<th><?php echo $this->Paginator->sort('Category.name', 'Category'); ?></th>

我希望这篇文章也可以帮助其他人:)

我还将测试此行为,看看我是否也可以省略所有绑定函数:https://github.com/siran/linkable/

蛋糕有很多插件,但蛋糕应该有插件的“认证”。在 github 上很难找到完全正常工作和测试过的 :)

我也想念 railscasts.com 这样的网站,只是为了蛋糕 :D

/MartOn

【问题讨论】:

  • 我同意你的观点,CakePHP 并不总是生成有效的查询。但是,我想知道其他 ORM 框架是否在这方面做得更好。最后,分析生成的 SQL 语句并(如果需要)尝试优化它们是一种很好的做法(就像您所做的那样)。我特别提到了如果需要,因为有时它真的取决于执行查询的频率,而优化至关重要。对于非常复杂的关系,可以使用自定义(原始 SQL)查询,但只能作为最后的手段。
  • 在这些情况下更简洁的解决方案是将您的(复杂)查询包装在“数据库视图”(CREATE VIEW post_with_category AS ... 并将其用作模型的数据库源。这样您的 CakePHP 模型可以保持简单,数据库视图将充当“抽象层”。dev.mysql.com/doc/refman/5.0/en/create-view.htmlIMO 尽可能尝试使用 CakePHP 查询,但如果事情变得如此复杂,请不要强迫自己使用它们它只会让你的代码更难理解和维护。

标签: cakephp


【解决方案1】:

是的,您必须使用 JOIN 才能根据关联的模型结果进行排序。

是的,您可以使用 JOIN 进行分页。只需在实际调用 $this-&gt;paginate(); 之前将您的选项(包括 JOIN)传递给您的分页。 (网上有很多关于如何使用 JOIN 进行分页的资源)

【讨论】:

  • 感谢您的快速回复。我真的很喜欢我的控制器尽可能干燥,所以我需要将它放入模型中。我不明白为什么 Cake 没有自动计算出这个,但我认为有几个原因:)
  • @Mart0n - Np。无论如何/所有与查询相关的东西都应该已经在您的模型中了。就个人而言,我宁愿他们按原样进行查询,并允许我在需要时加入。我通常会包含 8-10 个其他模型,并且执行 JOIN(s) 并不理想。
  • 嗨@Dave,不确定你的意思。我知道与模型相关的东西应该留在模型中。如果我想通过排序进行分页,加入或重新绑定似乎是 Cake 中的唯一选项
  • @Mart0n - 你不需要绑定/解除绑定/重新绑定任何东西 - 似乎比仅使用 JOIN 更复杂的 IMO。各有各的。最重要的是,您不能只使用关联和包含来返回按包含模型排序的数据。
  • 我在这里找到的解决方案是在 Mark Story 的博客上找到的。这就是我为什么要这样做的原因。我今天在一个大型数据库上对其进行了测试,效果很好。我现在只错过了一个左连接子查询以使其正常工作。
猜你喜欢
  • 2011-06-17
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
  • 1970-01-01
相关资源
最近更新 更多