4

我有一个 itemid 和一个 category id 都是有条件的。如果没有给出,则所有项目都显示为最新的拳头。如果给定了 itemid,则仅显示 id 低于给定 id 的项目(用于分页)。如果给定类别 id,则仅显示某个类别中的项目,如果同时给出两个类别,则仅显示某个类别中的项目 id 小于 itemid 的项目(按类别显示的项目下一页)。

因为参数是有条件的,所以在构建 SQL 字符串时,你会根据参数得到很多 if 语句(伪代码我用 php 的东西磨损了我的美元符号):

if itemid ' where i.iid < :itemid '
if catid 
  if itemid
     ' and c.id = :catid'
  else
     ' where c.id = :catid'  
  end if
end if

如果给出更多可选参数,这将变得非常混乱,所以我想我会试试 createQueryBuilder。希望有这样的事情:

    if($itemId!==false){
        $qb->where("i.id < :id");
    }
    if($categoryId!==false){
        $qb->where("c.id = :catID");
    }

可悲的是,事实并非如此,最后一个将覆盖第一个

我想出的是这个(在 Symfony2 中):

private function getItems($itemId,$categoryId){
    $qb=$this->getDoctrine()->getRepository('mrBundle:Item')
      ->createQueryBuilder('i');
    $arr=array();
    $qb->innerJoin('i.categories', 'c', null, null);
    $itemIdWhere=null;
    $categoryIdWhere=null;
    if($itemId!==false){
        $itemIdWhere=("i.id < :id");
    }
    if($categoryId!==false){
        $categoryIdWhere=("c.id = :catID");
    }
    if($itemId!==false||$categoryId!==false){
        $qb->where($itemIdWhere,$categoryIdWhere);
    }
    if($itemId!==false){
        $qb->setParameter(':id', $itemId);
    }
    if($categoryId!==false){
        $arr[]=("c.id = :catID");
            $qb->setParameter(':catID', $categoryId);
    }
    $qb->add("orderBy", "i.id DESC")
        ->setFirstResult( 0 )
        ->setMaxResults( 31 );

我并不完全信任它,$qb->where(null,null)尽管它目前没有产生错误或意外结果。看起来这些参数被忽略了。在文档中找不到任何内容,但空字符串会生成错误$qb->where('','')

它对我来说仍然有点笨拙,如果我可以使用多个,$qb->where(condition)那么每个可选只需要一个 if 语句$qb->where(condition)->setParameter(':name', $val);

所以问题是:有没有更好的方法?

我想如果学说有一个转义字符串的功能,我可以摆脱第二轮 if 语句(不确定恶意用户是否可以在允许 sql 注入的不同字符集中发布某些内容):

private function getItems($itemId,$categoryId){
    $qb=$this->getDoctrine()->getRepository('mrBundle:Item')
      ->createQueryBuilder('i');
    $arr=array();
    $qb->innerJoin('i.categories', 'c', null, null);
    $itemIdWhere=null;
    $categoryIdWhere=null;
    if($itemId!==false){
        $itemIdWhere=("i.id < ".
           someDoctrineEscapeFunction($id));
    }

感谢您阅读本文,希望您能启发我。

[更新]

我目前正在使用虚拟 where 语句,因此可以使用 andWhere 添加任何其他条件语句:

    $qb->where('1=1');// adding a dummy where
    if($itemId!==false){
        $qb->andWhere("i.id < :id")
          ->setParameter(':id',$itemId);
    }
    if($categoryId!==false){
        $qb->andWhere("c.id = :catID")
          ->setParameter(':catID',$categoryId);
    }
4

1 回答 1

1

如果您想使用更通用的方法来处理此问题,您可以创建过滤器。 Doctrine 2.2 具有过滤系统,允许开发人员将 SQL 添加到查询的条件子句中

阅读有关过滤器的更多信息,但是,我正在以与您展示的方式类似的方式处理此问题

于 2013-09-12T04:44:02.130 回答