我有一个实体User
,它与名为Session
的实体有一个OneToMany关系。
到目前为止,我可以做$myUser->getSessions()
并获得一个包含与$myUser
相关的所有会话的数组。
Session
与另一个实体Moment
也有OneToMany关系。
现在,这个Moment
实体已经转移到了一个文档中,因为该部分应用程序现在位于MongoDB数据库中,主要是为了解决性能问题。
为了让应用程序保持运行而不重写大量代码,我创建了一个像这样的Doctrine Listener:
class DoctrineListenerPostLoad
{
private $container;
private $dm;
public function __construct(Container $container, DocumentManager $dm)
{
$this->dm = $dm;
$this->container = $container;
}
public function postLoad(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if($entity instanceof Session)
{
$entity->setMoments(array());
$entity = $args->getEntity();
$moments = $this->dm->getRepository('AppBundle\Document\Moment')->findBy(array('idSession' => $entity->getId()));
$entity->setMoments($moments);
}
}
}
因此,当加载Session
的实例时,侦听器会获取与mongodb数据库中的会话相关的时刻。
但通过这样做,我失去了教条的懒惰负担。当我需要获得用户的所有会话(但不是时刻)时,由于数据量很大,我得到OutOfMemoryException
,因为它会加载时刻。
我知道我可以解开"解开" Session
和Moment
并在需要时执行DocRepo->findBy(array('idSession' => $entity->getId())
,但我必须在应用上重写很多运行良好的代码。
还有另外一种方法吗?就像在实体中加载DocumentManager(Yeks!)或检查是否在PostLoad
中调用了getter?
谢谢!
答案 0 :(得分:1)
1:使用Ocramius/ProxyManager包装数据库调用并推迟,直到某人尝试使用代理集合(应该非常简单)
2:手动制作未初始化的ODM PersistentCollection
。如果你假装@ReferenceMany(repositoryMethod="getBySession", targetDocument=Moment::class)
使用moments
,那么一切都应该正常工作,因为使用你编写的存储库方法将再次延迟加载集合(该方法将被赋予Session
对象作为第一个论点)。你的postLoad
大概会是这样的:
$mapping = [
'association' => \Doctrine\ODM\MongoDB\Mapping\ClassMetadata::REFERENCE_MANY,
'repositoryMethod' => 'getBySession',
'strategy' => 'setArray',
'targetDocument' => Moment::class,
];
$coll = $this->dm->getConfiguration()->getPersistentCollectionFactory()->create($this->dm, $mapping);
$coll->setOwner($entity, $mapping);
$coll->setInitialized(false);
$entity->setMoments($coll);
请注意,我可能错过了一些必需的$mapping
属性,这种方法可能永远不会起作用(尽管不应该在1.x中破坏)。如果你不想用参考映射“作弊”,你可能会将Session
映射为文档并直接用@ReferenceMany(repositoryMethod="getBySession", targetDocument=Moment::class)
映射时刻,但我不确定副作用。< / p>