【发布时间】:2010-03-14 23:24:42
【问题描述】:
我有 3 个数据库表:
- 文章
- article_has_tag(其他表的 2 个 FK)
- 标签
我目前显示了一个文章列表,文章的标签显示在下面,但随着列表变长,查询的数量也会增加。
我想遍历所有文章,依次从每篇文章中获取标签对象。
可以在 1 个推进查询中完成吗?
【问题讨论】:
我有 3 个数据库表:
我目前显示了一个文章列表,文章的标签显示在下面,但随着列表变长,查询的数量也会增加。
我想遍历所有文章,依次从每篇文章中获取标签对象。
可以在 1 个推进查询中完成吗?
【问题讨论】:
我相信您使用的是 symfony 1.0 和 Propel 1.2...虽然 cmets 中已经描述的方法讨论了替代方法,但至少有一种直接的方法可以解决您的问题:将此功能添加到您的 ArticlePeer类:
public static function getTaggedArticles()
{
$c = new Criteria();
//some filters here, e.g. LIMIT or Criteria::IN array
$ahts = ArticleHasTagPeer::doSelectJoinAll($c);
$articles = array();
foreach($ahts as $aht)
{
if(!isset($articles[$aht->getArticleId()]))
{
$articles[$aht->getArticleId()] = $aht->getArticle();
}
$articles[$aht->getArticleId()]->addTag($aht->getTag());
}
return $articles;
}
其中$ahts 是$article_has_tags 的缩写。在 Article 类 (protected array $collTags) 中创建一个简单的标签数组以及 addTag() 方法,如果它们不存在的话。
这只会执行一个 SQL 查询,但请认真考虑,如果没有我提到的过滤器,您可能会不必要地对数百个对象进行水合,这是对性能的重大影响。您可能想研究如何仅基于 doSelectRS() 调用进行水合 - 检查您的 BlahPeer 类以了解其 JOIN 方法的工作原理,然后检查 this link 以了解如何编写自定义 JOIN 方法。
无论哪种方式,该方法都会以 ArticleId 作为键构建一个唯一的文章数组 - 如果您需要不同的排序顺序,您可以再次对该数组进行排序,或者在构建集合时使用不同的数组键来组织集合.
【讨论】:
除非我误解了你的问题,否则不要循环任何内容,因为你会产生另一种膨胀。
执行单个查询,其中“article”连接到“article_has_tag”连接到“tag”。单个查询应返回指定的文章和它们所拥有标签的标签名称。
我自己使用 Doctrine,因此无法帮助您进行确切的查询,但谷歌搜索会显示如下内容:http://www.tech-recipes.com/rx/2924/symfony_propel_how_to_left_join/。
此外,symfony 权威指南(为 Propel 编写的)应该能够为您提供帮助。
【讨论】:
我假设您使用的是 Propel 1.3 或 1.4,但尚未使用 Propel 1.5(仍处于测试阶段),因为后者具有用于这些多个连接的 a very natural support(部分受到 Doctrine 语法的启发)。
如果您在数据库模式中定义了外键,您应该在 ArticleHasTagPeer 类中有一个静态的 doSelectJoinByAll 方法。如果使用此方法,相关的Article 和Tag 对象将使用相同的查询进行水合。您仍然可以传入修改Article 和Tag 选择标准的Criteria 对象。我知道这有点奇怪,因为您可能想从 Article 对象开始,这是 Propel 1.5 更改的驱动因素之一。在 Symfony 中,您还可以使用 DbFinderPlugin,这已经在 Propel 1.3 中为您提供了此功能(对于 Propel 1.4,它需要 a small patch)。事实上,Propel 1.5 主要由 DbFinderPlugin 的作者 François Zaniotto 编写。
【讨论】:
简短的回答是否。
但是通过一些努力,您仍然可以做到这一点。以下是选项列表:
doSelectPostWithUsersAndComments)。 【讨论】: