16

我应该如何在学说存储库查询中按鉴别器列进行排序?

我有一个非常简单的设置,我有不同类型的付款详细信息,可以是信用卡 (CC) 或借记单 (DO)。

所以我实现了一个单表继承映射策略来实现这一点,但是当我尝试按鉴别器列排序时,问题就出现了,因为基类中不存在鉴别器列。

存储库功能:

public function getPaymentDetails (ClientContactInterface $clientContact)
{
    $dql = 'SELECT pd
            from
            AccountingBundle:PaymentDetail pd
            JOIN ClientProductBundle:ClientProduct cp
            WITH cp.payment_detail_id = pd.id
            WHERE
            cp.payment_detail_id = pd.id
            and cp.client_contact_id = :client_contact_id
            GROUP BY pd.id
            ORDER BY pd.method_type'; // Since pd.method_type is the discriminator column, I cannot order by it. And I need to be able to.

    $em = $this->getEntityManager();
    $query = $em->createQuery($dql)->setParameter('client_contact_id', $clientContact->getId());
    return $query->getResult();
}

Base PaymentDetail 实体:

/**
 * @ORM\Entity(repositoryClass="AccountingBundle\Repository\PaymentDetailRepository")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\Table(name="PaymentDetails")
 * @ORM\DiscriminatorColumn(name="PaymentMethodType", type="string")
 * @ORM\DiscriminatorMap({ "DO" = "DOPaymentDetail", "CC" = "CCPaymentDetail"})
 */

class PaymentDetail implements PaymentDetailInterface
{

    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected  $id;

    /* etc... */
}

借记单 PaymentDetail 实体:

/**
 * AccountingBundle\Entity\DOPaymentDetail
 *
 * @ORM\Table(name="PaymentDetails")
 * @ORM\Entity
 */
class DOPaymentDetail extends PaymentDetail implements DOPaymentDetailInterface
{

    /**
     * @var string $account_holder
     *
     * @ORM\Column(name="DOAccountHolder", type="string", length=255)
     */
    protected $account_holder;

    /* etc... */
}

信用卡 PaymentDetail 实体:

/**
 * AccountingBundle\Entity\CCPaymentDetail
 *
 * @ORM\Table(name="PaymentDetails")
 * @ORM\Entity
 */
class CCPaymentDetail extends PaymentDetail implements CCPaymentDetailInterface
{

    /**
     *
     * @var string $card_holder
     *
     * @ORM\Column(name="CCCardHolder", type="string", length=255)
     */
    protected $card_holder;

    /* etc... */
}

当我尝试这样做时,我得到了这个错误,

Error: Class AccountingBundle\Entity\PaymentDetail has no field or association named method_type") 
4

3 回答 3

4

即使 TYPE 还没有实现到学说的核心,它仍然可以作为自定义用户函数来实现。

有人已经完成了一项了不起的工作并为我们实施了它。以防万一该资源将来会被删除,这里有一个针对 php7+ 的稍微调整的版本:

<?php
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\SqlWalker;

class TypeFunction extends FunctionNode
{
    /**
     * @var string
     */
    public $dqlAlias;

    public function getSql(SqlWalker $sqlWalker): string
    {
        /** @var ClassMetadataInfo $class */
        $class = $sqlWalker->getQueryComponent($this->dqlAlias)['metadata'];
        $tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $this->dqlAlias);

        if (!isset($class->discriminatorColumn['name'])) {
            $message = 'TYPE() only supports entities with a discriminator column.';
            throw QueryException::semanticalError($message);
        }

        return $tableAlias . '.' . $class->discriminatorColumn['name'];
    }

    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->dqlAlias = $parser->IdentificationVariable();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

现在,您可以通过执行以下操作按鉴别器列排序:

SELECT e, TYPE(e) AS HIDDEN my_type FROM Entity e ORDER BY my_type DESC;
于 2018-03-27T23:22:22.680 回答
1

似乎最简单的解决方案(到目前为止)是向基类添加另一个字段并复制鉴别器列值。

上述TYPE(q)仅适用于 WHERE 子句。

于 2014-08-20T16:59:31.603 回答
0

您可以尝试使用TYPE()orINSTANCE OF吗?

相关:https ://groups.google.com/forum/#!topic/doctrine-user/JtCbwuN-37o

但是,这个话题并没有说它是否被实施。在写它的时候,有人说 order by 行不通。

$dql = 'SELECT pd
        from
        AccountingBundle:PaymentDetail pd
        JOIN ClientProductBundle:ClientProduct cp
        WITH cp.payment_detail_id = pd.id
        WHERE
        cp.payment_detail_id = pd.id
        and cp.client_contact_id = :client_contact_id
        GROUP BY pd.id
        ORDER BY TYPE(pd)';
于 2013-11-25T16:45:11.960 回答