Doctrine PostLoad生命周期回调未在fetchJoin中执行

时间:2017-07-20 09:54:17

标签: symfony doctrine-orm

我遇到了Lifecycle Callback of Doctrine ORM的问题,这个问题没有在fetch-joined实体上执行,而是经常在延迟加载的实体上执行。

这是代码:

EntityA:

namespace AppBundle\Entity\EntityA;

use Doctrine\ORM\Mapping as ORM;

/**
 * EntityA
 * @ORM\Entity()
 * @ORM\HasLifecycleCallbacks()
 */
class EntityA {
    /**
     * @var int
     * @ORM\Id
     */
    private $id;

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

    /**
     * @var \Doctrine\Common\Collections\ArrayCollection
     * @ORM\OneToMany(targetEntity="EntityB", mappedBy="EntityA", indexBy="name", cascade="all", orphanRemoval=true)
     */
    private $entitiesB;

    /**
     * @var \Doctrine\Common\Collections\ArrayCollection
     */
    private $myNotMappedField;

    public function __construct() {
        /*initializes here fields mapped by Doctrine to db*/
        $this->name='';

        $this->initNotMappedFields();
    }

    /**
     * Here I initialize properties not handled by Doctrine
     * @ORM\PostLoad()
     */
    public function initNotMappedFields() {
        $this->myNotMappedField=new \Doctrine\Common\Collections\ArrayCollection();
    }
}

EntityB:

/**
 * EntityB

 * @ORM\Entity()
 * @ORM\HasLifecycleCallbacks()

 */
class EntityB {
    /**
     * @var int
     * @ORM\Id
     */
    private $id;

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


    /**
     * @var \Doctrine\Common\Collections\ArrayCollection
     * @ORM\ManyToOne(targetEntity="EntityA", inversedBy="entitiesB")
     */
    private $entityA


    /**
     * @var \Doctrine\Common\Collections\ArrayCollection
     */
    private $myNotMappedField;

    public function __construct() {
        /*initializes here fields mapped by Doctrine to db*/
        $this->name='';

        $this->initNotMappedFields();
    }

    /**
     * Here I initialize properties not handled by Doctrine
     * @ORM\PostLoad()
     */
    public function initNotMappedFields() {
        $this->myNotMappedField=new \Doctrine\Common\Collections\ArrayCollection();
    }
}

控制器:

// this works right:
// EntityA::initNotMappedFields() is properly called
$entityA = $this->getDoctrine()->getManager()->getRepository('AppBundle:EntityA')->findOneById(1); 
// EntityB::initNotMappedFields() is properly called
$entityA->getEntitiesB();

// I want to fetch join EntityB into EntityA, to avoid
// multiple single SQL statements to be executed against the DB
// EntityA::initNotMappedFields() is called
$entityA = $this->getDoctrine()->getManager()->getRepository('AppBundle:EntityA')->createQueryBuilder('entA')
    ->addSelect(['entB'])
    ->andWhere('entA=:id')->setParameter('id', $id)
    ->leftJoin('entA.entitiesB', 'entB')
    ->getQuery()->getOneOrNullResult();

// EntityB::initNotMappedFields() is NOT called
$entityA->getEntitiesB();

我错过了什么?

2 个答案:

答案 0 :(得分:1)

这是因为第一个示例将生成SQL查询以获取每个 EntityB ,然后将其加载到 EntityA 。如果A有10个B,那么您将获得10个额外的查询以获得在B上调用postLoad()回调的每个B,因为EntityManager是构建 EntityB 的回调。请参阅documentation on the postLoad() event

我要做的只是使用 EntityA EntityB 上调用您的初始化:

/**
 * Here I initialize properties not handled by Doctrine
 * @ORM\PostLoad()
 */
public function initNotMappedFields()
{
    $this->myNotMappedField = new \Doctrine\Common\Collections\ArrayCollection();

    // the 'if' here is in case you load EntityA without joining EntityB
    // so that you won't cause the extra queries if you don't want EntityB in there
    if ($this->entitiesB) {
        foreach ($this->entitiesB as $entityB) {
            $entityB->initNotMappedFields();
        }
    }
}

答案 1 :(得分:1)

答案是'是的,任何加载操作都会触发postLoad事件'。

https://github.com/doctrine/doctrine2/issues/6568

对于将来从谷歌来到这里的人来说,问题出在我的应用程序中,我在PostLoad中使用了根实体在fetchjoined实体的PostLoad中设置的一些信息,但当然没有人可以保证我一个PostLoad在其他PostLoad之前或之后执行。

他们将很快或之后被执行。

所以使用的方法是这里描述的https://stackoverflow.com/a/45216602/7135824