如何在学说2中选择鉴别列

Chi*_*Lee 6 php dql symfony doctrine-orm discriminator

当在下面运行DQL时,从doctrine 2中选择仅识别器列时,我需要一些帮助

SELECT p.type FROM AppBundle\Entity\Product p
Run Code Online (Sandbox Code Playgroud)

type 是实体中的鉴别列 AppBundle\Entity\Product

@ORM\DiscriminatorColumn(name="type", type="smallint")`

@ORM\DiscriminatorMap({
    "0" = "AppBundle\Entity\Product",
    "1" = "AppBundle\Entity\Product\SingleIssue",
    "2" = "AppBundle\Entity\Product\CountBasedIssue",
    "3" = "AppBundle\Entity\Product\TimeBasedIssue"
})
Run Code Online (Sandbox Code Playgroud)

我知道这type不是实体中的不动产,但无论如何我还能这样做吗?

提前致谢!

更新

阅读Doctrine代码2天后,我决定覆盖SqlWalker并通过下面的片段创建新的Hydrator

覆盖SqlWalker

<?php

namespace ...;

use Doctrine\ORM\Query\SqlWalker;

class CustomSqlWalker extends SqlWalker
{
    const FORCE_GET_DISCRIMINATOR_COLUMN = 'forceGetDiscriminatorColumn';
    const DISCRIMINATOR_CLASS_MAP = 'discriminatorClassMap';

    /**
     * {@inheritdoc}
     */
    public function walkSelectClause($selectClause)
    {
        $sql = parent::walkSelectClause($selectClause);
        $forceGetDiscriminatorColumn = $this->getQuery()->getHint(self::FORCE_GET_DISCRIMINATOR_COLUMN);
        if (empty($forceGetDiscriminatorColumn)) {
            return $sql;
        }

        foreach ($this->getQueryComponents() as $key => $queryComponent) {
            if (!in_array($key, $forceGetDiscriminatorColumn)) {
                continue;
            }

            $metadata = $queryComponent['metadata'];
            $discriminatorColumn = $metadata->discriminatorColumn['name'];
            $tableName = $metadata->table['name'];
            $tableAlias = $this->getSQLTableAlias($tableName, $key);
            $discriminatorColumnAlias = $this->getSQLColumnAlias($discriminatorColumn);
            $sql .= ", $tableAlias.$discriminatorColumn AS $discriminatorColumnAlias";
        }

        return $sql;
    }
}
Run Code Online (Sandbox Code Playgroud)

定制保湿器

<?php

namespace ...;

use Doctrine\ORM\Internal\Hydration\ArrayHydrator;
use PDO;

class CustomHydrator extends ArrayHydrator
{
    /**
     * {@inheritdoc}
     */
    protected function hydrateAllData()
    {
        $result = array();

        $rootClassName = null;
        if (isset($this->_hints['forceGetDiscriminatorColumn']) &&
            isset($this->_hints['discriminatorClassMap'])) {
            $rootClassName = $this->_hints['discriminatorClassMap'];
        }

        while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
            foreach ($data as $key => $value) {
                if ($this->hydrateColumnInfo($key) != null ||
                    empty($rootClassName)) {
                    continue;
                }

                $metadata = $this->getClassMetadata($rootClassName);
                $discriminatorColumn = $metadata->discriminatorColumn;
                $fieldName = $discriminatorColumn['fieldName'];
                $type = $discriminatorColumn['type'];
                $this->_rsm->addScalarResult(
                    $key, $fieldName, $type
                );
            }
            $this->hydrateRowData($data, $result);
        }

        return $result;
    }
}
Run Code Online (Sandbox Code Playgroud)

配置定制保湿器

orm:
    ...
    hydrators:
        CustomHydrator: YourNamespace\To\CustomHydrator
Run Code Online (Sandbox Code Playgroud)

最后一步

$query = $queryBuilder->getQuery();
$query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'YourNamespace\To\CustomSqlWalker');
$query->setHint(\YourNamespace\To\CustomSqlWalker::FORCE_GET_DISCRIMINATOR_COLUMN, array($rootAlias)); // this alias will be used in CustomSqlWalker class
$query->setHint(\YourNamespace\To\CustomSqlWalker::DISCRIMINATOR_CLASS_MAP, $this->getClassName()); // this full-qualify class name will be used in CustomHydrator class

$products = $query->getResult('CustomHydrator');
Run Code Online (Sandbox Code Playgroud)

TL; DR

我知道这是一个非常复杂的解决方案(可能仅适用于我的场景),所以我希望有人能给我另一个简单的方法来解决这个问题,非常感谢!

Mat*_*teo 9

无法直接访问鉴别器列.

可能会发生应查询特殊类型的实体的情况.由于没有直接访问鉴别器列,因此Doctrine提供了INSTANCE OF构造.

您可以使用INSTANCE OFDQL 查询实体的类型,如文档中所述.例如:

$query = $em->createQuery("SELECT product FROM AppBundle\Entity\AbstractProduct product WHERE product  INSTANCE OF AppBundle\Entity\Product");
$products = $query->getResult();
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助


Don*_*sto 6

我用这个小"黑客"

  1. 为您的实体定义通用接口(可选但建议)
  2. getType在此界面中创建方法
  3. 在Discriminator实体中创建常量
  4. 在每个受歧视的实体内返回适当的常量

这样你就可以检索鉴别器"通用"实体(Product在你的情况下)并调用getType它.

当然,如果你对直接由sql完成的结果过滤感兴趣,这根本不是一个解决方案,我担心,目前还没有任何解决方案可用.
如果您发现这个更好,请与我们分享.