Php Doctrine2:多态查询:搜索子类的属性

Php Doctrine2:多态查询:搜索子类的属性,php,doctrine-orm,Php,Doctrine Orm,我有一个处理客户订单的项目。其中一些订单是通过Amazon.com完成的。我有一个订单实体,还有一个AmazonOrder实体扩展了它。AmazonOrder增加的一个功能是AmazonOrderId 我需要实现广泛的搜索功能。用户可以在文本框中输入一些内容,并在一个大where子句中的一组表达式中使用。因此,例如,如果用户搜索“111”,结果包括ID以111开头的任何订单、发送到以111开头的邮政编码的任何订单、发送到“111 Main St”的任何订单,等等 这些东西是通过查询生成器创建的查

我有一个处理客户订单的项目。其中一些订单是通过Amazon.com完成的。我有一个订单实体,还有一个AmazonOrder实体扩展了它。AmazonOrder增加的一个功能是AmazonOrderId

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

这些东西是通过查询生成器创建的查询实现的,该查询具有一个大的
orX()
表达式

现在,我想对所有的订单进行匹配,但如果他们是亚马逊订单,也要对亚马逊订单进行匹配

我被困住了,我怀疑这可能是不可能的

下面是我如何建立查询的:

$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();
我不知道如何添加一个条件,粗略地说,“或者(Order是一个AmazonOrder和类似于“$userQuery%”的AmazonOrderId)。”


有人有什么见解吗?或者是一种处理方法,或者至少是一种确认这种方法不可行的方法?

嗯,我在上一个条令项目中遇到了类似的问题

有一次,它只是一个字段,所以我把它移到父类中——这不是最好的解决方案,但很有效。在另一种情况下,存在太多的属性,因此这些属性会使父类变得混乱。我执行了一个本地sql查询来搜索和获取记录ID,然后使用
WHERE IN(…)
dql来获取实体

一个折衷方案可能是可以将本机sql查询直接映射到实体的原则,尽管每次使用它时,我都发现使用起来相当笨拙,而且上面概述的两个查询(fetch-id和fetch-entites)的开销是可以忽略的


也许你可以用
WHERE
子句中的
INSTANCEOF
操作符来完成一些事情,尽管我不认为条令会聪明到能够以你想要的方式识别它

这是另一个适用于我的原则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);
您只需在实体本身的特定子类上加入实体。(您可以根据您的用例调整我的简单查询。)


我只尝试过一次,但似乎有效。

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

...->from('From', 'X')->leftJoin('App\Entity\Class\Name', 'Y', \Doctrine\ORM\Query\Expr\Join::WITH, 'Y.id = X.id')
请注意,由于它是左连接,因此会带来性能上的冲击

还要注意的是,无论您在做什么,条令都会自动连接映射超类的所有子实体

关于这种行为,github存在一个问题:

我想补充一点,如果您不需要访问
子类
的任何字段,您可以
加入
超类
并使用子类的
where实例进行过滤。
我建议您将鉴别器列和超类
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
任何相关的子实体


我只想分享这一切,因为它帮助了我。

谢谢Max。我现在通过使用UI解决了这个问题。它不是最优的,我很快会重新考虑它。我真的不想把东西移到超类。听起来我认为没有直接的解决办法是对的。当我再次讨论这个问题时,如果我有什么聪明的想法,我会让你知道的。即使对于具有复合键的实体,这也很有效。如果我能再次投票支持这个答案,我会这么做!谢谢你!在DQL中记录:从Order LEFT中选择o加入AmazonOrder ao,o.id=ao.idIn原则2.1,抛出致命错误:达到最大函数嵌套级别“1000”,您甚至可以查询特定的子类集。左键连接您需要的所有子类,并添加一个where子句,该子句要求您的结果是其中一个子类的实例<代码>从订单左侧选择o将AmazonOrder ao与o.id=ao.id左连接将EbayOrder eo与o.id=eo.id左连接,其中(o AmazonOrder实例或o EbayOrder实例)
这样将排除可能存在的任何其他订单实体。