在运行下面的DQL
时,从doctrine 2中选择仅识别器列时需要一些帮助SELECT p.type FROM AppBundle\Entity\Product p
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"
})
我知道type
不是实体中的真实财产,但无论如何我还能这样做吗?
提前致谢!
阅读Doctrine代码2天后,我决定覆盖SqlWalker并通过以下片段创建新的Hydrator
<?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;
}
}
<?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;
}
}
orm:
...
hydrators:
CustomHydrator: YourNamespace\To\CustomHydrator
$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');
我知道这是一个非常复杂的解决方案(可能只是针对我的情况),所以我希望有人能给我另一个简单的方法来解决这个问题,非常感谢!
答案 0 :(得分:9)
无法直接访问鉴别器列。
可能需要查询特殊类型的实体。 因为没有直接访问鉴别器列, 学说提供了INSTANCE OF构造。
您可以使用INSTANCE OF
DQL as described in the docs查询实体类型。例如:
$query = $em->createQuery("SELECT product FROM AppBundle\Entity\AbstractProduct product WHERE product INSTANCE OF AppBundle\Entity\Product");
$products = $query->getResult();
希望这有帮助
答案 1 :(得分:5)
我使用这个小&#34; hack&#34;
getType
方法通过这种方式,您可以检索鉴别器&#34; generic&#34;实体(在您的情况下为Product
)并在其上调用getType
。
当然,如果您对sql直接完成的结果过滤感兴趣,这根本不是解决方案,我担心,目前还没有任何解决方案。<登记/> 如果你发现这个更好,请与我们分享。
答案 2 :(得分:0)
您应该能够使用带有INSTANCE OF
和case, when, (else,) end
子句的标量结果来做到这一点:
SELECT
(case
when p INSTANCE OF AppBundle\Entity\Product then \'0\'
when p INSTANCE OF AppBundle\Entity\Product\SingleIssue then \'1\'
when p INSTANCE OF AppBundle\Entity\Product\CountBasedIssue then \'2\'
when p INSTANCE OF AppBundle\Entity\Product\TimeBasedIssue then \'3\'
else \'foobar\'
end) as type
FROM
AppBundle\Entity\Product p
当然,缺点是每次添加DiscriminatorMap
条目时都必须更新查询。