Symfony2,Doctrine,延迟加载和代理类问题

Posted

技术标签:

【中文标题】Symfony2,Doctrine,延迟加载和代理类问题【英文标题】:Symfony2, Doctrine, Lazy Loading and Proxy Class issue 【发布时间】:2014-08-20 04:04:35 【问题描述】:

首先,我要感谢 *** 社区在过去几年中为我提供的所有帮助!我通常会找到解决方案,但这一次,经过数小时的研究和测试,我无法得到任何解决方案。所以这是我的问题:

在我的页面顶部,我有一个从带有类别的数据库生成的菜单。这是我的代码的一部分:

类别控制器:

public function renderMenuAction() 

    $em = $this->getDoctrine()->getManager();
    $manager = new CategoryManager($em);
    $request = $this->getRequest();

    $categories = $manager->loadMenu();

    foreach($categories as $category) 
        $this->getLocalizedCategoryTranslations($category, $request);
    

    return $this->render('HeidanCoreBundle:Includes/Category:category_menu.html.twig', array(
        'categories' => $categories,
    ));


我的经理的函数 loadMenu 引用了这个请求,以获取 lvl0 类别:

CategoryRepository:

public function findMenuElements() 

    $qb = $this->_em->createQueryBuilder();

    $qb->select('category', 'translation')
       ->from('HeidanCoreBundle:Category', 'category')
       ->leftJoin('category.translations', 'translation')
       ->where('category.lvl = 0')
       ;

    return $query = $qb->getQuery()
            ->getResult();


getLocalizedCategoryTranslations 调用设置类别翻译值(标题、描述等)的侦听器

public function getLocalizedCategory(TranslatableEvent $event)

    $object = $event->getObject();
    $locale = $event->getLocale();

    if($object instanceof TranslatableInterface) 
        if(get_class($object) == 'Heidan\CoreBundle\Entity\Category') 
            $this->localizeObject($object, $locale);
            $this->localizeCategoryChildren($object, $locale);
        
    


这是我的问题:此代码在任何页面上都可以正常工作,但对元素有自定义请求的页面除外。

索引控制器

public function indexAction()


    $news = $this->getNews();
    $announcements = $this->getAnnouncements();

    return $this->render('HeidanCoreBundle:Public:index.html.twig', array(
        'news' => $news,
        'announcements' => $announcements,
    ));


public function getNews() 

    $em = $this->getDoctrine()->getManager();
    $qb = $em->createQueryBuilder();

    $qb->select('article')
       ->from('HeidanCoreBundle:Article', 'article')
       ->orderBy('article.createdAt', 'DESC')
       ->setMaxResults(4);

    $query = $qb->getQuery();

    $results = $query->getResult();

    return $results;


这是我的菜单的描述。

管理页面(没有像上面的 getNews 这样的自定义查询 - 所有这些对象都是类别):

--文章

----社会

----商业

--艺术品

----书籍

----歌曲

--艺术家

----作者

----歌手

索引页面(有一个请求文章的 getNews 查询):

--不翻译

----没有翻译

----没有翻译

--艺术品

----书籍

----歌曲

--艺术家

----作者

----歌手

如您所见,对象翻译未显示在索引页面上。我检查了 Symfony 调试模式,根本没有要求。 (对于 ID 为 1、13、14 的类别没有选择翻译查询来获取翻译,而对于其他类别的查询已完成)。

我尝试了几种方法:

如果我删除 getNews() 并将其替换为 null,则它正在索引页面上工作。

如果我添加 $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);在我的 getNews 函数结束时:它也在索引页面上工作!

如果我将 getNews 函数替换为 getArtist(根据菜单),设置为“无翻译”的 Artist 菜单类别也会出现同样的问题

我认为这是 Doctrine 的延迟加载问题,但也许有一些我不明白的地方。

如果您有任何想法,我正在等待您的帮助!提前致谢!

【问题讨论】:

请问,如果您对 SO 这么感兴趣,为什么要为这个问题创建一个新帐户? 第一次参加,在这里提问。所以这是我在 *** 上的第一个帐户。 【参考方案1】:

在使用调试器后,我终于设法找到了解决方案。我的第一个虽然是一半对,一半错。问题是由于 Doctrine 行为造成的,但它来自我的代码行。

public function getLocalizedCategory(TranslatableEvent $event)

    $object = $event->getObject();
    $locale = $event->getLocale();

    if($object instanceof TranslatableInterface) 
        if(get_class($object) == 'Heidan\CoreBundle\Entity\Category') 
            $this->localizeObject($object, $locale);
            $this->localizeCategoryChildren($object, $locale);
        
    


在这个函数中(我编辑了问题也让这部分代码出现)我调用 get_class 方法。

我在使用调试器的时候发现,当我调用getNews()方法(返回Article对象)时,返回的Category(只针对有Articles的Category)不是Heidan\CoreBundle\的对象Entity\CategoryProxies__CG__\Heidan\CoreBundle\Entity\Category

因此,这将我的条件 if(get_class($object) == 'Heidan\CoreBundle\Entity\Category') 设置为 false 并且未翻译类别

为了获得正确的行为,我必须将实体管理器注入我的事件并使用函数 getClassMetadata 获取类名

正确的getLocalizedCategory函数:

public function getLocalizedCategory(TranslatableEvent $event)

    $object = $event->getObject();
    $locale = $event->getLocale();
    $em = $event->getEm();

    if($object instanceof TranslatableInterface) 
        $className = $em->getClassMetadata(get_class($object))->getName();
        if($className == 'Heidan\CoreBundle\Entity\Category') 
            $this->localizeObject($object, $locale);
            $this->localizeCategoryChildren($object, $locale);
        
    


这个链接帮助了我Get entity name from class object

希望这对其他人有所帮助。

【讨论】:

以上是关于Symfony2,Doctrine,延迟加载和代理类问题的主要内容,如果未能解决你的问题,请参考以下文章

从doctrine2中的代理对象获取“true”对象

Symfony2 和 Doctrine:一对多关系

使用 Doctrine 和 Symfony2 查询多对多关系

Symfony Doctrine ORM ManyToMany - 带有标签的博客 - 我没有从博客中获取所有标签,没有延迟加载

Symfony2/Doctrine 提交表单需要很长时间

Symfony2 / Doctrine中的实体和模型有啥区别