【问题标题】:Leave out discriminator part of Doctrine' generated SQL省略 Doctrine 生成的 SQL 的鉴别器部分
【发布时间】:2013-12-05 09:45:55
【问题描述】:

假设以下AbstractPage 模型:

/*
 *     @ORM\Entity
 *     @ORM\Table(name="page")
 *     @ORM\InheritanceType("SINGLE_TABLE")
 *     @ORM\DiscriminatorColumn(name="type", type="string")
 *     @ORM\DiscriminatorMap
 *     ({
 *         "page" = "Page",
 *         "link" = "Link"
 *     })
 */

还有以下 DQL 查询:

SELECT p FROM \Page\Model\AbstractPage

生成的 SQL 将是:

SELECT ... FROM page p0_ WHERE p0_.type IN ('page', 'link')

现在的问题是:如何从该查询中删除 WHERE 子句。在更复杂的查询中,WHERE 子句的这一部分使得无法使用某些已定义的索引。这可以通过在索引中添加type 来解决,但这会使我的索引变大,我觉得这没有必要。

AbstractPage 是继承树中的根。因此我们对表中的所有记录感兴趣。省略 WHERE 部分正是如此。

所以问题是:我怎样才能让 Doctrine 在不需要的地方删除这个 WHERE 部分。

谢谢!

【问题讨论】:

  • 对于它的价值:使用 Doctrine 2.2,我没有这个 WHERE 部分,但我有一个不同之处:我没有使用 SINGLE_TABLE, JOINED。我不知道是版本还是这个设置改变了 WHERE。
  • 遗憾:版本不同!
  • 你使用哪个版本的学说?

标签: php sql doctrine-orm indexing dql


【解决方案1】:

这是我能想到的解决方案。这个想法是扩展一些学说类以添加所需的功能。 保持模型现在的样子。

创建扩展 SqlWalker 的新类(当然更新命名空间)

<?php

namespace Sad;


use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\SqlWalker;

class CustomSqlWalker extends SqlWalker
{

  const IGNORE_DISCRIMINATION = 'ignoreDiscrimination';

  /**
   * {@inheritdoc}
   */
  public function walkWhereClause($whereClause)
  {
    // Get list of aliases in which discrimination should be ignored
    $ignoreDescription = $this->getQuery()->getHint(self::IGNORE_DISCRIMINATION);
    if ($ignoreDescription !== false) {
      // For each aliases...
      foreach ($this->getQueryComponents() as $k => $component) {
        // ...check if alias is in ignore list
        if (in_array($k, $ignoreDescription)) {
          /** @var $metaObj ClassMetadata */
          $metaObj = $component['metadata'];
          // Update inheritance type to disable discrimination where
          if ($metaObj->isInheritanceTypeSingleTable()) {
            $metaObj->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_NONE);
          }
        }
      }
    }
    return parent::walkWhereClause($whereClause);
  }
}

然后进行查询,您执行以下操作:

echo $entityManager->createQuery("SELECT p FROM \Sad\Schema\AbstractPage as p")->getSQL();
// Output: ELECT p0_.id AS id_0, p0_.name AS name_1, p0_.type AS type_2 FROM page p0_ WHERE p0_.type IN ('page', 'link')

$query = $entityManager->createQuery("SELECT p FROM \Sad\Schema\AbstractPage as p");
// Make sure query uses custom walker
$query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Sad\CustomSqlWalker');
// Specify which aliases should ignore discrimination
$query->setHint(\Sad\CustomSqlWalker::IGNORE_DISCRIMINATION, array('p'));

echo $query->getSQL();
// Output: ELECT p0_.id AS id_0, p0_.name AS name_1, p0_.type AS type_2 FROM page p0_

【讨论】:

  • 不客气。扩展 Query 和 SqlWalker 是相当困难的。许多方法被标记为私有并且查询类是最终的。所以这是唯一可以做的。当然可以通过添加输入参数验证等来改进代码。
猜你喜欢
  • 1970-01-01
  • 2014-07-22
  • 1970-01-01
  • 2019-04-01
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
相关资源
最近更新 更多