多对多关系querybuilder doctrine和symfony2扩展查询

时间:2016-09-17 12:58:55

标签: symfony doctrine-orm many-to-many

我正在使用querybuilder应用以下查询,但不知何故,很多2关系没有按预期工作。

$shopData = $sm->createQueryBuilder()                    
                ->select('v')
                ->from('AdminBundle:Voucher','v')
                ->innerJoin('v.shop', 's')
                ->leftJoin('AdminBundle:VoucherProgram', 'vp', \Doctrine\ORM\Query\Expr\Join::ON, 'vp.id = v.program_id')
                ->leftJoin('AdminBundle:shopHistory', 'sh', \Doctrine\ORM\Query\Expr\Join::ON, 'sh.shop = s.id')
                ->where('s.shopStatus = :shopStatus')
                ->setParameter('shopStatus', Shop::SHOP_ACTIVATED)
                ->andWhere('s.highlightedHome = :highlightedHome')
                ->setParameter('highlightedHome', Shop::SHOP_HIGHLIGHTED_HOME)
                ->andWhere('s.offers = \'voucher\'')
                ->setFirstResult(0)
                ->setMaxResults(6)
                ->addOrderBy('v.discount_amount', 'DESC')
                ->groupBy('sh.shop')
                ->getQuery()
                ->getSql();

生成的查询如下所示:

SELECT v FROM AdminBundle:Voucher v INNER JOIN v.shop s LEFT JOIN AdminBundle:VoucherPrograms vp ON vp.id = v.program_id LEFT JOIN AdminBundle:shopHistory sh ON sh.shop = s.id WHERE s.shopStatus = :shopStatus AND s.highlightedHome = :highlightedHome AND s.offers = 'voucher' GROUP BY sh.shop ORDER BY v.discount_amount DESC

如果我删除了所有内容并且只保留了Many2Many关系的内连接,那么它正在按预期工作。

$sm->createQueryBuilder()                    
                ->select('v')
                ->from('AdminBundle:Voucher','v')
                ->innerJoin('v.shop', 's');

以下是生成的查询:

SELECT l0.* FROM voucher l0_ INNER JOIN shop_voucher l2_ ON l0_.id = l2_.voucher_id INNER JOIN shop l1_ ON l1_.id = l2_.shop_id;

所以我想知道为什么当我添加更多连接时系统没有找到正确的关系。

这是我与Many2Many关系的主要实体:

Shop.php

namespace AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Shop.
 *
 * @ORM\Table(name="shop")
 * @ORM\Entity(repositoryClass="AdminBundle\Entity\ShopRepository")
 */
class Shop
{
    const SHOP_DEACTIVATED = 0;
    const SHOP_ACTIVATED = 1;
    const SHOP_HIGHLIGHTED_HOME = 1;
    ................................
    /**
     * @ORM\ManyToMany(targetEntity="Voucher", inversedBy="shop")
     * @ORM\JoinTable(name="shop_voucher")
     */
    private $voucher;
    ................................

Voucher.php

namespace AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
#use Doctrine\Common\Collections\ArrayCollection;

/**
 * Voucher.
 *
 * @ORM\Table(name="voucher")
 * @ORM\Entity(repositoryClass="AdminBundle\Entity\VoucherRepository")
 */
class Voucher
{
    ................................
    /**
     * @ORM\ManyToMany(targetEntity="Shop", mappedBy="voucher", cascade={"persist"})    
     */
    private $shop;
    ................................

我已经检查过具有相同问题的堆栈,但我想知道如何扩展查询。我有我的问题的解决方案,如下所示,但没有得到上述场景中正在发生的事情。

$shopDataQuery = $connection->prepare('SELECT v.* FROM voucher AS v INNER JOIN shop_voucher AS sv ON sv.voucher_id = v.id INNER JOIN shop AS s ON s.id = sv.shop_id LEFT JOIN voucher_programs AS vp ON vp.id = v.program_id LEFT JOIN shop_history AS sh ON sh.shop = s.id WHERE s.shopStatus = :shopStatus AND s.highlightedHome = :highlightedHome AND s.offers = 'voucher' GROUP BY sh.shop ORDER BY v.discount_amount DESC LIMIT 6');

更新

这是shopHistory.php

namespace AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * shopHistory.
 *
 * @ORM\Table(name="shop_history")
 * @ORM\Entity(repositoryClass="AdminBundle\Entity\shopHistoryRepository")
 */
class shopHistory
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var int
     * @ORM\ManyToOne(targetEntity="Shop", inversedBy="shopHistory")
     * @ORM\JoinColumn(name="shop", referencedColumnName="id")
     */
    private $shop;

这是VoucherProgram.php

namespace AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * VoucherProgram.
 *
 * @ORM\Table(name="voucher_program")
 * @ORM\Entity(repositoryClass="AdminBundle\Entity\VoucherProgramRepository")
 */
class VoucherProgram
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="Voucher", mappedBy="program")
     */
    private $voucher;

    /**
     * @ORM\OneToMany(targetEntity="Shop", mappedBy="vprogram")
     */
    private $shop;

2 个答案:

答案 0 :(得分:2)

我认为这是因为您已将您的关系命名为与您的字段相同:

SELECT v 
FROM AdminBundle:Voucher v 
INNER JOIN v.shop s 
LEFT JOIN AdminBundle:VoucherPrograms vp ON vp.id = v.program_id 
LEFT JOIN AdminBundle:shopHistory sh ON sh.shop = s.id 
WHERE s.shopStatus = :shopStatus 
AND s.highlightedHome = :highlightedHome 
AND s.offers = 'voucher' 
GROUP BY sh.shop 
ORDER BY v.discount_amount DESC

尝试在 shopHistory 中重命名 shop_id 字段购物

但我没有完整的实体模型来进行测试!

如果不是这样,请尝试粘贴5个实体的代码,请...

修改:

我使用symfony 2.8版本在本地计算机上进行测试。

我已经生成了给定模型的实体。

我刚刚在凭证实体中添加了这个:

/**
 * @ORM\ManyToOne(targetEntity="voucherProgram", inversedBy="voucher")
 */
private $program;

我有这个疑问:

我的第一个查询

SELECT v 
FROM AppBundle:Voucher v 
INNER JOIN v.shop s 
LEFT JOIN AppBundle:voucherProgram vp WITH vp.id = v.program 
LEFT JOIN AppBundle:shopHistory sh 
WITH sh.shop = s.id 
GROUP BY sh.shop

我的第二个SQL查询

SELECT v0_.id AS id0, v0_.program_id AS program_id1 
FROM voucher v0_ 
INNER JOIN shop_voucher s2_ ON v0_.id = s2_.voucher_id 
INNER JOIN shop s1_ ON s1_.id = s2_.shop_id 
LEFT JOIN voucher_program v3_ ON (v3_.id = v0_.program_id) 
LEFT JOIN shop_history s4_ ON (s4_.shop = s1_.id) 
GROUP BY s4_.shop 
LIMIT 6 
OFFSET 0

我认为生成的内容是正确的!

编辑2:

我尝试使用symfony标准版:

$shopData = $this->getDoctrine()
  ->getManager()
  ->createQueryBuilder()                    
  ->select('v')
  ->from('AppBundle:Voucher','v')
  ->innerJoin('v.shop', 's')
  ->leftJoin('AppBundle:voucherProgram', 'vp', 'WITH', 'vp.id = v.program')
  ->leftJoin('AppBundle:shopHistory', 'sh', 'WITH', 'sh.shop = s.id')
  //->where('s.shopStatus = :shopStatus')
  //->setParameter('shopStatus', Shop::SHOP_ACTIVATED)
  //->andWhere('s.highlightedHome = :highlightedHome')
  //->setParameter('highlightedHome', Shop::SHOP_HIGHLIGHTED_HOME)
  //->andWhere('s.offers = \'voucher\'')
  ->setFirstResult(0)
  ->setMaxResults(6)
  //->addOrderBy('v.discount_amount', 'DESC')
  ->groupBy('sh.shop')
  ->getQuery()
  ->getDql();

我的composer.json是:

"php": ">=5.3.9",
"symfony/symfony": "2.8.*",
"doctrine/orm": "^2.4.8",
"doctrine/doctrine-bundle": "~1.4",
"symfony/swiftmailer-bundle": "~2.3",
"symfony/monolog-bundle": "~2.4",
"sensio/distribution-bundle": "~5.0",
"sensio/framework-extra-bundle": "^3.0.2",
"incenteev/composer-parameter-handler": "~2.0"

我的实体:

<强>商店

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Shop
 *
 * @ORM\Table(name="shop")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ShopRepository")
 */
class Shop
{
    const SHOP_DEACTIVATED = 0;
    const SHOP_ACTIVATED = 1;
    const SHOP_HIGHLIGHTED_HOME = 1;

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @ORM\ManyToMany(targetEntity="Voucher", inversedBy="shop")
     * @ORM\JoinTable(name="shop_voucher")
     */
    private $voucher;
}

<强> shopHistory

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * shopHistory
 *
 * @ORM\Table(name="shop_history")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\shopHistoryRepository")
 */
class shopHistory
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @var int
     * @ORM\ManyToOne(targetEntity="Shop", inversedBy="shopHistory")
     * @ORM\JoinColumn(name="shop", referencedColumnName="id")
     */
    private $shop;
}

<强>券

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Voucher
 *
 * @ORM\Table(name="voucher")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\VoucherRepository")
 */
class Voucher
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @ORM\ManyToMany(targetEntity="Shop", mappedBy="voucher", cascade={"persist"})    
     */
    private $shop;

    /**
     * @ORM\ManyToOne(targetEntity="voucherProgram", inversedBy="voucher")
     */
    private $program;
}

<强> voucherProgram

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * voucherProgram
 *
 * @ORM\Table(name="voucher_program")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\voucherProgramRepository")
 */
class voucherProgram
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="Voucher", mappedBy="program")
     */
    private $voucher;

    /**
     * @ORM\OneToMany(targetEntity="Shop", mappedBy="vprogram")
     */
    private $shop;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
}

答案 1 :(得分:1)

据我所知,第一个给定的查询是DQL查询,第二个是SQL查询。 DQL查询可以更短,并且仍然可以按预期工作,因为它不运行表而是有效。因此,您需要较少的连接来加入m2m关系(在生成final SQL时会扩展为双连接)

如果使用给定的查询构建器生成DQL,我发现生成的DQL没有任何问题。