Php Doctrine2 QueryBuilder没有明确匹配任何内容
我使用的是Doctrine 2.4,我有一个抽象基类,它包含如下方法:Php Doctrine2 QueryBuilder没有明确匹配任何内容,php,symfony,doctrine-orm,abstract-class,query-builder,Php,Symfony,Doctrine Orm,Abstract Class,Query Builder,我使用的是Doctrine 2.4,我有一个抽象基类,它包含如下方法: protected function getBaseQueryBuilder($type) { switch ($type) { case self::TYPE_1; return $this->em->createQueryBuilder()->...lots of clauses...; case self::TYPE_2;
protected function getBaseQueryBuilder($type) {
switch ($type) {
case self::TYPE_1;
return $this->em->createQueryBuilder()->...lots of clauses...;
case self::TYPE_2;
return $this->em->createQueryBuilder()->...lots of clauses...;
/* many more types... */
case self::TYPE_N;
return /* want to return a query builder for the empty set */
}
}
有几个从这个基类继承的子类,每个子类从几个地方调用这个方法。然后,在执行查询生成器之前,它们使用其他特定于类的子句扩展返回的查询生成器。但是,对于类型_N
,任何行都不能匹配
当然,一种解决方案是为$type==type\N
返回null,让每个调用方检查null
,如果是,则不执行任何操作。但是,如果我能返回一个查询生成器,它将永远不会匹配任何东西,并且查询甚至不会命中数据库,那就更好了。这将大大简化许多调用方站点
有什么方法可以做到这一点吗?你为什么要这样做?我想说的是,您不应该创建一个昂贵的
QueryBuilder
对象,只是为了在以后调用getResult()
时从中获取null
我建议您重新设计您的解决方案,也许可以在拉取getBaseQueryBuilder
方法和从查询生成器获得实际结果之间添加一个额外的方法。例如:
protected function getBaseQueryBuilder($type) {
switch ($type) {
case self::TYPE_1;
return $this->em->createQueryBuilder()->...lots of clauses...;
case self::TYPE_2;
return $this->em->createQueryBuilder()->...lots of clauses...;
case self::TYPE_N;
return null;
}
}
protected function getResultFromBaseQueryBuilder() {
$type = $this->getType(); // get your type
$queryBuilder = $this->getBaseQueryBuilder($type);
if( $queryBuilder === null ){
return /* empty result set so for example null, [] or new ArrayCollection(); */
}
return $queryBuilder->getResult();
}
您也可以直接在该方法中检查类型:
protected function getBaseQueryBuilder($type) {
switch ($type) {
case self::TYPE_1;
return $this->em->createQueryBuilder()->...lots of clauses...;
case self::TYPE_2;
return $this->em->createQueryBuilder()->...lots of clauses...;
}
}
protected function getResultFromBaseQueryBuilder() {
$type = $this->getType(); // get your type
if( $type === self:TYPE_N ){
return /* empty result set so for example null, [] or new ArrayCollection(); */
}
$queryBuilder = $this->getBaseQueryBuilder($type);
return $queryBuilder->getResult();
}
换句话说,与其制作一个包含
getBaseQueryBuilder
方法的公共接口,不如制作一个包含返回结果的方法的接口。(我建议您调用方法getResult
,而不是getResultFromBaseQueryBuilder
,我只是用它来澄清示例)
Acme\Doctrine\TypeQuery
Acme\Doctrine\TypeQueryBuilder
然后,在您的getBaseQueryBuilder
调用中,您可以根据提供的类型添加子句或返回TypeNQueryBuilder
protected function getBaseQueryBuilder($type)
{
$queryBuilder = $this->em->createQueryBuilder();
switch ($type) {
case self::TYPE_1:
$queryBuilder
->yadaYadaYada(....)
;
break;
case self::TYPE_2:
$queryBuilder
->yadaYadaYada(....)
;
break;
case self::TYPE_N:
return new TypeNQueryBuilder($this->em);
}
return $queryBuilder;
}
在界面相同的情况下,您只能使用
$this
->getBaseQueryBuilder($type)
->andWhere(...)
->addOrderBy(...)
->getQuery()
->getOneOrNullResult();
。。根据给定的类型,它要么正确地构建查询,要么在最后一分钟退出并返回您的
null
结果。我理解构建一个昂贵的对象以在最后不返回任何内容是浪费的。然而,在我看来,您的解决方案似乎不支持我所描述的我需要的东西:几个子类将获得这样的查询生成器,然后在执行之前向其添加更多子句。我看不出您的解决方案如何实现这一点,因为构建了查询生成器并立即执行其查询。子类的作用在哪里?基于你在评论中给我的一点信息,很难给你一个建议。例如,您可以为您的服务创建一个addClause
或addExpression
方法,但我觉得可能有更好的方法来实现您的目标。也许你可以问另一个问题,在那里你可以添加更多的细节来解释你的用户案例?您还可以在子类内部检查是否得到一个QueryBuilder
实例,并简单地忽略您有TYPE\u N
的情况(因此没有QueryBuilder
,向永远不会执行的查询添加子句没有多大意义).我需要的用例已在原始问题中描述。那么,您能否更具体地说明丢失了哪些信息?是的,我可以检查子类,正如我在原始问题中已经提到的。这个问题特别是关于不这样做,因为那将需要编写更多的代码。@jlh否决我的答案不会激励我花更多的时间来帮助你。我否决它是因为它不适用于我在原始问题中描述的用例。我认为这是一个公平的理由,这就是投票的目的。如果你不想在这上面花更多的时间,我理解。我目前正在尝试Qoopmao的解决方案。我喜欢这个解决方案。它甚至可以扩展为覆盖和where()
,orderBy()
等,以使这些操作更加便宜。我将尝试实现它,并看看它是如何运行的。我认为大多数方法,如和where
,innerJoin
,等等,都会做一些事情,然后调用add
,这样您就可以覆盖它,只返回$this
,并省去很多工作。
protected function getBaseQueryBuilder($type)
{
$queryBuilder = $this->em->createQueryBuilder();
switch ($type) {
case self::TYPE_1:
$queryBuilder
->yadaYadaYada(....)
;
break;
case self::TYPE_2:
$queryBuilder
->yadaYadaYada(....)
;
break;
case self::TYPE_N:
return new TypeNQueryBuilder($this->em);
}
return $queryBuilder;
}
$this
->getBaseQueryBuilder($type)
->andWhere(...)
->addOrderBy(...)
->getQuery()
->getOneOrNullResult();