【问题标题】:Update a many-to-many relationship in Doctrine更新 Doctrine 中的多对多关系
【发布时间】:2011-05-17 15:45:23
【问题描述】:

我有文章-类别关系,我想在必要时更新该关系。这意味着,从文章中添加或删除所需的类别。我使用带有 Doctrine 1.2 的 php (ZF) 设置。在 YAML 中,配置看起来(简化)如下:

Article:
  columns:
    id: bigint(10)

Category:
  columns:
    id: bigint (10)
  relations:
    articles:
      foreignAlias: categories
      class: Article
      refClass: CategoryArticle

CategoryArticle:
  columns:
    category_id: bigint (10)
    article_id: bigint (10)
  relations:
    category:
      class: Category
      foreignAlias: categoryArticle
    article:
      class: Article
      foreignAlias: categoryArticle

我有一个持久化的 $article,其中所有旧类别都可用。通过 POST 请求,我得到一个类别 id 列表,应该是新的。到目前为止我有这个:

$oldCategories = array();
foreach ($article->categories as $cat) {
    $oldCategories[] = $cat->id;
}
$newCategories = $form->getValue('categories');

$diffRemove = array_diff($oldCategories, $newCategories);
$diffAdd    = array_diff($newCategories, $oldCategories);
foreach ($diffRemove as $id) {
    // Remove all the categories $id from article [1]
}
foreach ($diffAdd as $id) {
    // Add all the categories $id to article [2]
}

我的问题是关于 [1] 和 [2]。添加和删​​除多对多关系的最佳性能是什么?

【问题讨论】:

  • 您使用的是哪个版本的学说?

标签: php database zend-framework doctrine many-to-many


【解决方案1】:

删除

在 SQL 中批量删除最有效的方法是使用单个 sql 语句并设置一些条件,例如

delete from Products where id>3

它利用索引、分区等。

有一种方法可以使用 Doctrine 1.2 实现该性能价值 - 使用 DQL DELETE 语句。如文档所示,以下查询转换为上述 SQL:

$q = Doctrine_Query::create()
    ->delete('Products p')
    ->where('p.id > 3');

在您的情况下,您可以使用类似的方法优化删除

$q = Doctrine_Query::create()
    ->delete('CategoryArticle ca')
    ->where('ca.article_id=?', $article_id)
    ->andWhereIn('ca.category_id', $diffRemove);

此代码应生成如下内容:

delete from CategoryArticle 
where article_id = $article_id and category_id in ($diffremove)

插入

通过插入,您可以使用CategoryArticle 实体。使用 Doctrine 最有效的方法是建立一个实体集合,而不是保存该集合:

$collection = new Doctrine_Collection('CategoryArticle');
foreach ($diffAdd as $id){
    $ca = new CategoryArticle();
    $ca->category = $id;
    $ca->article = $article_id;
    $collection[] = $ca;
}

$collection->save();

【讨论】:

  • 感谢您的评论!您为我的问题提供了一个很好的选择,我自己偶然发现了“集合插入”。对于删除,我现在使用另一个稍微不同的 foreach 循环:$q = $obj->getTable()->getQueryObject()->delete('CategoryArticle ca')。然后在循环中添加一个 orWhere() 子句:$q->orWhere('ca.article_id=? AND ca.category_id=?, array($articleId, $categoryId))。因此,这使得嵌套 where 子句,我能够删除 1 个查询(!)中的所有旧文章。
  • 好吧,使用您的方法,您最终会得到类似于delete from CategoryArticle where article_id = 1 or article_id = 2 or article_id = 3 or article_id = 4 ...的删除查询。我认为这不会影响性能,但这是一个非常冗长的查询:) ,也许我遗漏了一些东西,但您的查询可能会删除与其他文章的关联。尝试使用 $q->getSqlQuery() 输出实际的 SQL 并查看其中是否存在 category_id 条件。如果否 - 您有删除应保留的关联的风险。
  • 词穷了 :)。使用andWhereIn,查询非常短:只需delete from CategoryArticle where article_id in (1,2,3,4) and category_id = *category_id*
  • 啊,我误读了您的查询。 andWhereIn() 确实可以解决问题。我的方法也很有效,因为它创建了查询delete from CategoryArticle where (article_id=1 AND category_id=2) OR (article_id=1 AND category_id=3)。但是您的查询仍然更合适。
  • 啊,对了,单orWhere有两个条件。我已将其作为单独的 orWhereandWhere 阅读。不知道怎么回事,可能是我的眼睛在耍我。
猜你喜欢
  • 2012-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-30
  • 2014-09-14
相关资源
最近更新 更多