Symfony 2 - findall() 数据库查询太多

Symfony 2 - findall() too many DB queries

如果我使用以下代码,为什么 Symfony2 执行 40 个数据库查询:

$em = $this->getDoctrine()->getManager();
$records = $em->getRepository('MyWebBundle:Highlight')->findAll();

我认为 findAll() 方法 returns 只有来自 Highlight 实体和与其他实体的关联的所有项目替换 Proxy 对象。但是现在 findAll() 方法获取所有关联实体。

你知道问题出在哪里吗?

indexAction

public function indexAction() {
    $em = $this->getDoctrine()->getManager();
    $records = $em->getRepository('MyWebBundle:Highlight')->findAll();

    $csrf = $this->get('security.csrf.token_manager');
    $token = $csrf->refreshToken(self::FORM_TOKEN_ID);

    $params = array(
        "data" => array(
            "all" => $records,
        ),
        "token" => $token->getValue(),
        "static" => array(
            "add" => $this->generateUrl("admin_highlight_add"),
            "edit" => $this->generateUrl("admin_highlight_edit"),
            "del" => $this->generateUrl("admin_highlight_del"),
        ),
    );
    $ser = $this->get('jms_serializer');
    $jsonContent = $ser->serialize($params, 'json');

    return array('jsonContent' => $jsonContent);
}

突出实体

namespace My\WebBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;

/**
 * Highlight
 *
 * @JMS\ExclusionPolicy("none")
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="My\WebBundle\Entity\HighlightRepository")
 */
class Highlight {

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

    /**
     * @var string
     *
     * @ORM\Column(name="abbreviation", type="string", length=8, unique=true)
     */
    private $abbreviation;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="string", length=80, nullable=true)
     */
    private $description;

    /**
     * @var string
     *
     * @ORM\Column(name="color", type="string", length=7)
     */
    private $color;

    /**
     * @var ArrayCollection
     * @ORM\OneToMany(targetEntity="Goods", mappedBy="highlight")
     */
    private $goods;

    /**
     * @var ArrayCollection
     * @ORM\OneToMany(targetEntity="Calibration", mappedBy="highlight")
     */
    private $calibrations;

    /**
     * Constructor
     */
    public function __construct() {
        $this->goods = new \Doctrine\Common\Collections\ArrayCollection();
        $this->calibrations = new \Doctrine\Common\Collections\ArrayCollection();
    }

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

    /**
     * Set abbreviation
     *
     * @param string $abbreviation
     * @return Highlight
     */
    public function setAbbreviation($abbreviation) {
        $this->abbreviation = $abbreviation;

        return $this;
    }

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

    /**
     * Set description
     *
     * @param string $description
     * @return Highlight
     */
    public function setDescription($description) {
        $this->description = $description;

        return $this;
    }

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

    /**
     * Set color
     *
     * @param string $color
     * @return Highlight
     */
    public function setColor($color) {
        $this->color = $color;

        return $this;
    }

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

    /**
     * Add goods
     *
     * @param \My\WebBundle\Entity\Goods $goods
     * @return Highlight
     */
    public function addGood(\My\WebBundle\Entity\Goods $goods) {
        $this->goods[] = $goods;

        return $this;
    }

    /**
     * Remove goods
     *
     * @param \My\WebBundle\Entity\Goods $goods
     */
    public function removeGood(\My\WebBundle\Entity\Goods $goods) {
        $this->goods->removeElement($goods);
    }

    /**
     * Get goods
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getGoods() {
        return $this->goods;
    }

    /**
     * Add calibrations
     *
     * @param \My\WebBundle\Entity\Calibration $calibrations
     * @return Highlight
     */
    public function addCalibration(\My\WebBundle\Entity\Calibration $calibrations) {
        $this->calibrations[] = $calibrations;

        return $this;
    }

    /**
     * Remove calibrations
     *
     * @param \My\WebBundle\Entity\Calibration $calibrations
     */
    public function removeCalibration(\My\WebBundle\Entity\Calibration $calibrations) {
        $this->calibrations->removeElement($calibrations);
    }

    /**
     * Get calibrations
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getCalibrations() {
        return $this->calibrations;
    }

}

突出显示存储库为空

我认为问题出在序列化器上。由于您序列化了 highliths,它们中的每一个都具有序列化的属性,这意味着将对检索到的 Goods 执行惰性查询,这些 Goods 也将被序列化。

然后您应该通过添加注释来突出显示商品 属性 来防止这种行为

use ...
use JMS\SerializerBundle\Annotation\ExclusionPolicy;
use JMS\SerializerBundle\Annotation\Exclude;

/**
 * ...
 * @ExclusionPolicy("none")
 */
 class Highlight
{

   /**
    * ...
    * @Exclude
    */
   private $goods;

}

您可以从 JMSSerializer doc

中获得有关排除策略的更多详细信息

findAll 本身并不执行很多查询。当您通过 getter 访问相关实体时,将执行查询。由于关系不是急切获取的,它们是在您访问它们时第一次获取的。

我认为序列化程序访问所有子对象以发送您的对象。

Doctrine documentation

Whenever you have a managed entity instance at hand, you can traverse and use any associations of that entity that are configured LAZY as if they were in-memory already. Doctrine will automatically load the associated objects on demand through the concept of lazy-loading.

要防止这种情况,请禁用子序列化或使用 fetch EAGER 或构建 DQL 查询,它会与父对象一起预取所有子对象,例如(只是示例,不是有效的 DQL)

SELECT Highlight, Good, Calibration
FROM Highlights Highlight
LEFT JOIN  Highlight.googs Good
LEFT JOIN  Goog.calibrations Calibration
WHERE ...