我对 Doctrine ORM 的生命周期回调有问题,它不在 fetch 连接的实体上执行,而它经常在延迟加载的实体上执行。
这是代码:
实体 A:
namespace AppBundleEntityEntityA;
use DoctrineORMMapping as ORM;
/**
* EntityA
* @ORMEntity()
* @ORMHasLifecycleCallbacks()
*/
class EntityA {
/**
* @var int
* @ORMId
*/
private $id;
/**
* @var string
*
* @ORMColumn(type="string", length=255, nullable=true)
*/
private $name;
/**
* @var DoctrineCommonCollectionsArrayCollection
* @ORMOneToMany(targetEntity="EntityB", mappedBy="EntityA", indexBy="name", cascade="all", orphanRemoval=true)
*/
private $entitiesB;
/**
* @var DoctrineCommonCollectionsArrayCollection
*/
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
* @ORMPostLoad()
*/
public function initNotMappedFields() {
$this->myNotMappedField=new DoctrineCommonCollectionsArrayCollection();
}
}
实体 B:
/**
* EntityB
* @ORMEntity()
* @ORMHasLifecycleCallbacks()
*/
class EntityB {
/**
* @var int
* @ORMId
*/
private $id;
/**
* @var string
*
* @ORMColumn(type="string", length=255, nullable=true)
*/
private $name;
/**
* @var DoctrineCommonCollectionsArrayCollection
* @ORMManyToOne(targetEntity="EntityA", inversedBy="entitiesB")
*/
private $entityA
/**
* @var DoctrineCommonCollectionsArrayCollection
*/
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
* @ORMPostLoad()
*/
public function initNotMappedFields() {
$this->myNotMappedField=new DoctrineCommonCollectionsArrayCollection();
}
}
控制器:
// 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();
我错过了什么?
发生这种情况是因为第一个示例将生成一个 SQL 查询来获取每个单独的实体 B,然后将其加载到实体 A中。 如果 A 有 10 个 B,你将获得 10 个额外的查询来获取每个 B 在 B 上调用您的postLoad()
回调,因为 EntityManager 是构造实体 B的那个。 请参阅有关postLoad((事件的文档。
我要做的是简单地使用实体 A在实体 B上调用您的初始化:
/**
* Here I initialize properties not handled by Doctrine
* @ORMPostLoad()
*/
public function initNotMappedFields()
{
$this->myNotMappedField = new DoctrineCommonCollectionsArrayCollection();
// 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();
}
}
}
答案是"是的,任何加载操作都会触发 postLoad 事件"。
https://github.com/doctrine/doctrine2/issues/6568
对于那些将来从谷歌到达这里的人来说,问题出在我的应用程序中,我在根实体的 PostLoad 中使用了一些在 fetchjoin 实体的 PostLoad 中设置的信息,但肯定没有人能保证一个 PostLoad 在另一个 PostLoad 之前或之后执行。
他们很快就会被处决。
因此,使用方法是此处描述的方法 https://stackoverflow.com/a/45216602/7135824