【问题标题】:Can I mimic doctrine's lazy load on postLoad我可以在 postLoad 上模仿教义的延迟加载吗
【发布时间】:2018-03-09 09:58:13
【问题描述】:

我有一个实体User,它与一个名为Session 的实体存在OneToMany 关系。 到目前为止一切顺利,我可以做$myUser->getSessions() 并获得一个包含与$myUser 相关的所有会话的数组。

Session 还与另一个实体 Moment 建立了 OneToMany 关系。

现在,这个 Moment 实体已移至 Document 中,因为应用程序的该部分现在位于 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 数据库中获取与会话相关的时刻。 但是这样做我就失去了教义的懒惰负担。当我需要获取用户的所有会话(但不是 Moments)时,由于数据量很大,我会得到一个 OutOfMemoryException,因为它确实会加载时刻。

我知道我可以“取消绑定”SessionMoment 并在需要时执行 DocRepo->findBy(array('idSession' => $entity->getId()),但我将不得不在应用程序上重写很多运行良好的代码。 还有其他方法吗?比如可能在实体中加载 DocumentManager(是的!)或者检查是否在 PostLoad 中调用了 getter ?

谢谢!

【问题讨论】:

    标签: orm doctrine symfony-2.8 doctrine-odm


    【解决方案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) 映射时刻,但我不确定副作用。

    【讨论】:

    • 谢谢!看起来很有希望,我会在星期一试一试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多