Symfony 原则2:在单表继承中,在一对多关联中获取所有具有或不具有匹配记录的记录

Symfony 原则2:在单表继承中,在一对多关联中获取所有具有或不具有匹配记录的记录,symfony,orm,doctrine-orm,Symfony,Orm,Doctrine Orm,我试图找到总计数的清单在每个类别的基础上上市的位置 我想做的是,如果一个来自美国的用户访问该站点,只会显示该位置的记录。侧边栏上的category小部件还应考虑该位置每个类别下的列表总数。如果访问者点击芝加哥,小部件应该重新计算以反映“芝加哥”的位置 使用下面的代码 public function findCategoriesWithTotalListing($location) { $builder = $this->_em->createQueryBuilder(

我试图找到总计数的清单在每个类别的基础上上市的位置

我想做的是,如果一个来自美国的用户访问该站点,只会显示该位置的记录。侧边栏上的category小部件还应考虑该位置每个类别下的列表总数。如果访问者点击芝加哥,小部件应该重新计算以反映“芝加哥”的位置

使用下面的代码

    public function findCategoriesWithTotalListing($location)
{
    $builder = $this->_em->createQueryBuilder();

    $builder->select('c, count(l.id) AS num')
       ->from('Bundle\AdvertBundle\Entity\Category', 'c')
       ->leftJoin('c.listings','l')
       ->leftJoin('l.country','co')
       ->leftJoin('l.state','st')
       ->leftJoin('l.city','ci');

    $builder->groupBy('c.id');

    $result = $builder->getQuery()->getArrayResult();
    print_r($result);
    exit;
}
我能够检索所有类别,每个列表的总计数不带location参数

但是,如果我引入location参数,则仅检索在该位置具有列表的类别

    public function findCategoriesWithTotalListing($location)
{
    $builder = $this->_em->createQueryBuilder();

    $builder->select('c, count(l.id) AS num')
       ->from('Bundle\AdvertBundle\Entity\Category', 'c')
       ->leftJoin('c.listings','l')
       ->leftJoin('l.country','co')
       ->leftJoin('l.state','st')
       ->leftJoin('l.city','ci');

    $orx = $builder->expr()->orX();
    $orx->add($builder->expr()->like("co.slug", ':location'));
    $orx->add($builder->expr()->like("st.slug", ':location'));
    $orx->add($builder->expr()->like("ci.slug", ':location'));

    $builder->andWhere($orx);
    $builder->groupBy('c.id');
    $builder->setParameter('location',$location);

    $result = $builder->getQuery()->getArrayResult();
    print_r($result);
    exit;
}
我要所有类别

我可能做错了什么

谢谢

以下实体

类别实体

<?php

namespace Bundle\AdvertBundle\Entity;

use Bundle\FrameworkBundle\Entity\BaseEntity;
use Bundle\FrameworkBundle\Entity\DocumentInterface;
use Doctrine\ORM\Mapping as ORM;

/**
* Category
*
* @ORM\Table(name="listings_categories")
* @ORM\Entity(repositoryClass="Bundle\AdvertBundle\Repository\CategoryRepository")
*/
class Category extends BaseEntity implements DocumentInterface
{

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="title", type="string", length=255, precision=0, scale=0, nullable=false, unique=false)
 */
private $title;

/**
 * @var string
 *
 * @ORM\Column(name="slug", type="string", length=255, precision=0, scale=0, nullable=false, unique=false)
 */
private $slug;

/**
 * @var string
 *
 * @ORM\Column(name="summary", type="text", precision=0, scale=0, nullable=false, unique=false)
 */
private $summary;

/**
 * @var integer
 *
 * @ORM\Column(name="parent", type="integer", precision=0, scale=0, nullable=false, unique=false)
 */
private $parent;

/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\OneToMany(targetEntity="ListingItem", mappedBy="category")
 */
private $listings;

/**
 * @var string
 *
 * @ORM\Column(name="thumbnail", type="string", length=255, precision=0, scale=0, nullable=true, unique=false)
 */
private $thumbnail;

/**
 * @var string
 *
 * @ORM\Column(name="form_template", type="string", length=255, precision=0, scale=0, nullable=true, unique=false)
 */
private $formTemplate;


private $children;


private $totalChildren;

private $totaListing;


/* Getters and Setters*/


}
国家实体
namespace Bundle\LocationBundle\Entity;

use Bundle\FrameworkBundle\Entity\DocumentInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * Country
 *
 * @ORM\Table(name="locations")
 * @ORM\Entity(repositoryClass="Bundle\LocationBundle\Repository\LocationRepository")
 */
class Country extends Location
{

/**
 * Set countryCode
 *
 * @param string $countryCode
 * @return Country
 */
public function setCountryCode($countryCode)
{
    $this->countryCode = $countryCode;

    return $this;
}

/**
 * Get countryCode
 *
 * @return string 
 */
public function getCountryCode()
{
    return $this->countryCode;
}
}

州和城市实体就像国家一样

,你在那里过滤掉所有不匹配的类别,因此它无法计算它们。应该可以通过一个查询完成,但您必须将条件从何处移动,以获取甚至不匹配的行,并将它们计为0。

在教义中没有IF,但你可以使用

CASE WHEN (<cond>) THEN 1 ELSE 0
CASE WHEN()然后是1,否则为0
当您使用$orx expr时

另一个可能性是将条件移动到那些连接中,如中所示,但随后您必须执行任意连接原则,以指定自定义:

来自文档:任意连接语法(来自用户u JOIN注释c,其中c.User=u.id) 然后,将这三个联接表的三个计数相加。这是可行的,但很难看


或者@denys281所述的子查询-仅从类别中选择,但select子句包含统计每个类别的所有匹配列表的列。

在原则中研究子查询几天后,我终于得到了适用于我的情况的代码。 下面是一些让我重新思考如何编写第一个代码的例子

  • 我需要所有类别
  • 我需要统计每个类别中的所有列表
  • 仅选择与传入的位置参数相关的列表
  • 列表与位置有多对一的关联
  • 显而易见的解决方案是使用@danys281建议的子查询

        public function findCategoriesWithTotalListing($location)
    {
        $subQuery = $this->_em->createQueryBuilder();
        $subQuery->select('COUNT(l.id)')
                 ->from('Bundle\AdvertBundle\Entity\ListingItem','l')
                 ->leftJoin('l.category','cat')
                 ->leftJoin('l.country','co')
                 ->leftJoin('l.state','st')
                 ->leftJoin('l.city','ci')
                 ->where('cat.id = c.id');  
    
        if($location instanceOf Country){
            $subQuery->andWhere('co.slug = :location');
        }
    
        if($location instanceOf State){
            $subQuery->andWhere('st.slug = :location');    
        }
    
        if($location instanceOf City){
            $subQuery->andWhere('ci.slug = :location');
        }
    
        $subQuery->andWhere("l.status = :status");
    
    
        $builder = $this->_em->createQueryBuilder();
        $builder->select("c, (".$subQuery->getDql().") AS num")
           ->from('Bundle\AdvertBundle\Entity\Category', 'c')
           ->setParameters(['location'=>$location->getSlug(),'status'=>'active'])
           ->groupBy('c');
    
        return $builder->getQuery()->getResult();
    }
    

    谢谢大家给我的提示。

    如果您想在一个查询中统计每个类别中的项目,我认为您必须使用子查询。现在,您可以计算所有类别中具有相同位置的项目。或者你可以只做3个单独的查询,计算每个类别中的项目。是的,我想从访客当前位置计算每个类别下的所有项目,所以我认为你需要子查询,或者3个单独的查询。
    SELECT c.*, sum(IF(loc.code = 'x', 1, 0))
    FROM category c
    LEFT JOIN list l ON c.id = l.c_id
    LEFT JOIN loc ON loc.id = l.loc_id
    GROUP BY c.id
    
    CASE WHEN (<cond>) THEN 1 ELSE 0
    
        public function findCategoriesWithTotalListing($location)
    {
        $subQuery = $this->_em->createQueryBuilder();
        $subQuery->select('COUNT(l.id)')
                 ->from('Bundle\AdvertBundle\Entity\ListingItem','l')
                 ->leftJoin('l.category','cat')
                 ->leftJoin('l.country','co')
                 ->leftJoin('l.state','st')
                 ->leftJoin('l.city','ci')
                 ->where('cat.id = c.id');  
    
        if($location instanceOf Country){
            $subQuery->andWhere('co.slug = :location');
        }
    
        if($location instanceOf State){
            $subQuery->andWhere('st.slug = :location');    
        }
    
        if($location instanceOf City){
            $subQuery->andWhere('ci.slug = :location');
        }
    
        $subQuery->andWhere("l.status = :status");
    
    
        $builder = $this->_em->createQueryBuilder();
        $builder->select("c, (".$subQuery->getDql().") AS num")
           ->from('Bundle\AdvertBundle\Entity\Category', 'c')
           ->setParameters(['location'=>$location->getSlug(),'status'=>'active'])
           ->groupBy('c');
    
        return $builder->getQuery()->getResult();
    }