我可以在postLoad上

时间:2018-03-09 09:58:14

标签: orm doctrine symfony-2.8 doctrine-odm

我有一个实体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,因为它会加载时刻。

我知道我可以解开"解开" SessionMoment并在需要时执行DocRepo->findBy(array('idSession' => $entity->getId()),但我必须在应用上重写很多运行良好的代码。 还有另外一种方法吗?就像在实体中加载DocumentManager(Yeks!)或检查是否在PostLoad中调用了getter?

谢谢!

1 个答案:

答案 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>