我可以在 postLoad 上模仿 doctrine 的延迟加载吗

Can I mimic doctrine's lazy load on postLoad

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

我知道我可以 "unbind" SessionMoment 并在需要时做 DocRepo->findBy(array('idSession' => $entity->getId()),但我将不得不重写很多很好的工作应用程序上的代码。 还有别的办法吗?就像在实体中加载 DocumentManager(是的!)或检查是否在 PostLoad ?

中调用了 getter

谢谢!

1:使用 Ocramius/ProxyManager 包装数据库调用并延迟,直到有人尝试使用代理集合(应该非常简单)

2:手动制作未初始化的 ODM PersistentCollection。如果你假装使用 @ReferenceMany(repositoryMethod="getBySession", targetDocument=Moment::class) 作为 moments,一切都应该正常工作,因为集合将再次使用你编写的存储库方法 lazy-loaded(该方法将被赋予 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 中中断)。如果您不想 "cheat" 使用参考映射,您可以将映射 Session 作为文档并直接使用 @ReferenceMany(repositoryMethod="getBySession", targetDocument=Moment::class) 映射时刻,但我不确定 [=28] =].