Doctrine2:Polymorphic Queries:搜索子类的属性

时间:2011-10-11 00:20:07

标签: php doctrine-orm

我有一个项目,我处理客户订单。其中一些订单是通过Amazon.com进行的。所以我有一个Order实体,以及一个扩展它的AmazonOrder实体。 AmazonOrder添加的一件事是AmazonOrderId。

我需要实施广泛的搜索功能。用户可以在文本框中输入一些内容,并在一个大的where子句中用于一堆表达式。因此,例如,如果用户搜索“111”,则结果包括任何ID为111的订单,任何以111开头的邮政编码,任何订单运送到“111 Main St”等。

这些内容是使用查询生成器创建的查询实现的,该查询具有较大的orX()表达式。

现在,我想与所有订单匹配,但如果它们是AmazonOrder,也会匹配AmazonOrderId。

我被卡住了 - 我怀疑它可能不可能

以下是我构建查询的方法:

$qb->select('o,s')->from('PMS\Entity\Order', 'o');    
$qb->leftJoin('o.shippingInfo','s');
$qb->andWhere('o.status = :status');
$qb->setParameter('status',$status);
$qb->andWhere(
    $qb->expr()->orX(
        $qb->expr()->like('o.id',':query')
        $qb->expr()->like('s.address',':query')
        $qb->expr()->like('s.city',':query')
    )
);
$qb->setParameter('query',$userQuery .'%');

$orders = $qb->getQuery()->getResult();

我无法弄清楚如何添加一个大致上说“OR(订单是AmazonOrder和AmazonOrderId LIKE'$ userQuery%')”的条件“

任何人都有任何见解?要么是处理这个问题的方法,要么是至少确认这样做不可行?

3 个答案:

答案 0 :(得分:23)

这是另一个适用于Doctrine 2.4的解决方案:

$qb->select('o')
   ->from('Order', 'o')
   ->leftJoin('AmazonOrder', 'ao', 'WITH', 'o.id = ao.id')
   ->andWhere('o.id like :query or ao.amazonOrderId like :query')
   ->setParameter('query', $someQuery);

您只需将实体左侧加入其自身的特定子类。 (您可以根据用例调整我的简单查询。)

我已经尝试了一次,但似乎有效。

答案 1 :(得分:2)

嗯,我在上一个学说项目中遇到了类似的问题。

有一次它只是一个字段,所以我把它移到了父类 - 不是最好的解决方案,但是有效。在其他一些情况下,有太多属性,所以这些将使父类混乱。我做了一个原生的SQL查询,用于搜索和获取记录ID,然后使用WHERE IN (...) dql来获取实体。

折衷可能是可以直接将本机sql查询映射到实体的原则ResultSetMapping,尽管每次使用它时我都发现它使用起来非常笨拙并且两个查询的开销很大(fetch id& amp;如上所述可以忽略不计。

也许你可以在你的INSTANCEOF条款中使用WHERE运算符来完成某些事情,尽管我不认为教义会足够智能以你想要的方式识别它。

答案 2 :(得分:0)

如果您需要加入一个子类以获取仅存在于该子类中的字段,则可能需要使用以下语法:

...->from('From', 'X')->leftJoin('App\Entity\Class\Name', 'Y', \Doctrine\ORM\Query\Expr\Join::WITH, 'Y.id = X.id')

请注意,由于它是左联接,因此会带来性能上的损失。

还请注意,无论您在做什么,该学说都会自动加入映射超类的所有子实体。

有关此行为的github问题:https://github.com/doctrine/orm/issues/5980

我想补充一点,如果您不需要访问subclasses的任何字段,则只需join superclass并使用where INSTANCE OF subclass进行过滤。 我建议您将鉴别符列和superclass id添加到索引中,如下所示:

* @ORM\Table(indexes={@ORM\Index(name="idx_partition_type", columns={"id", "type"})})
* ...
* @ORM\DiscriminatorColumn(name="type", columnDefinition="CHAR(1) NOT NULL")
abstract class superclass{
   ...
}

这仅对不可实例化的抽象类有用。否则,如果您的班级不是抽象的,则无论发生什么情况,学说都会leftJoin任何相关的子实体。

我只是想分享所有这些内容,因为它对我有帮助。