Symfony3 / Doctrine2 中 $em->clear() 时出现未定义索引错误

Posted

技术标签:

【中文标题】Symfony3 / Doctrine2 中 $em->clear() 时出现未定义索引错误【英文标题】:Undefined index error when $em->clear() in Symfony3 / Doctrine2 【发布时间】:2017-01-20 09:02:29 【问题描述】:

我收到此错误:

[Symfony\Component\Debug\Exception\ContextErrorException] 注意:未定义索引:000000000fa82729000000006e17190b

我已经尝试了this post的所有提示。

我的代码比其他发帖者的代码简单多了(问这个问题)。

    $em = $this->getContainer()->get('doctrine')->getManager();
    $pictureUrlRepository = new ProductItemPictureUrlRepository($em);
    $pictures = $pictureUrlRepository->findAll();

    for ($i = 0; $i < 4; ++$i) 
        $productItem = $pictures[$i]->getProductItem();
        dump($productItem->getId());
        $fileName = 'file_' . $i;

        $productItemPicture = new ProductItemPicture();
        $productItemPicture->setProductItem($productItem);
        $productItemPicture->setFile($fileName);
        $productItemPicture->setPosition(1);
        $productItemPicture->setSize(1000);
        $productItemPicture->setWidth(1200);
        $productItemPicture->setHeight(1000);

        $em->persist($productItemPicture);
        $em->flush();
        $em->clear();
        unset($productItemPicture);
    

为了向您展示,我已经尝试了上面链接中的建议,这里是更复杂的代码以及已实现的提示(但结果仍然相同):

      $em = $this->getContainer()->get('doctrine')->getManager();
    $pictureUrlRepository = new ProductItemPictureUrlRepository($em);
    $pictures = $pictureUrlRepository->findAll();

    foreach ($em->getEventManager()->getListeners() as $event => $listeners) 
        foreach ($listeners as $listener) 
            $em->getEventManager()->removeEventListener($event, $listener);
        
    

    $batchSize = 2;
    for ($i = 0; $i < 4; ++$i) 
        $productItem = $pictures[$i]->getProductItem();
        dump($productItem->getId());
        $fileName = 'file_' . $i;

        $productItemPicture = new ProductItemPicture();
        $productItemPicture->setProductItem($productItem);
        $productItemPicture->setFile($fileName);
        $productItemPicture->setPosition(1);
        $productItemPicture->setSize(1000);
        $productItemPicture->setWidth(1200);
        $productItemPicture->setHeight(1000);
        $productItemPicture->setCreated(new \DateTime('20.1.2017'));
        $productItemPicture->setUpdated(new \DateTime('20.1.2017'));

        $em->persist($productItemPicture);
        if (($i % $batchSize) === 0) 
            $em->flush();
            $em->clear();
        
    
    $em->flush();
    $em->clear();

当我评论(禁用)$em->clear();行,它的工作原理。不运行 clear() 有什么问题? 在执行数千个数据库条目但不运行 clear() 时会发生什么?

【问题讨论】:

能否请您标记出此错误的“行”?也许来自你在循环之后执行的代码? 当我评论 $em->clear();有用。所以这是行。 你有多少张照片? 5?少一点? 也许,但您正在清除 EntityManager,如果您在循环后尝试更新其他实体,这将引发您提供的异常。 @Veve 我有数千张图片,但为了测试,我减少到 4 张,以表明它仍然会导致这个问题。涉及此问题的其他线程与内存泄漏有关,因此我将此测试缩减为 4,以触发此错误。 【参考方案1】:

我发现了我的问题所在。

在开始迭代循环之前,我使用 FindAll() 方法获得所有结果。然后我通过引用该方法的数组结果来设置 $productItem。但是迭代周期中的 clear() 会破坏该数组中的实体 ID。

当我查看有关 batch processing 的 Doctrine 网站示例时,我更关心 clear() 部分。但真正的问题是他们如何获得迭代的结果。他们对 createQuery() 结果使用 iterate() 方法。

所以,更新后的代码,工作结果是这样的:

    $em = $this->getContainer()->get('doctrine')->getManager();
    $q = $em->createQuery('select p from AppBundle\Model\Product\Item\ProductItemPictureUrl p');
    $iterableResult = $q->iterate();

    $i = 0;
    foreach ($iterableResult as $row) 
        $productItem = $row[0]->getProductItem();
        dump($productItem->getId());
        $fileName = 'file_' . $i;

        $productItemPicture = new ProductItemPicture();
        $productItemPicture->setProductItem($productItem);
        $productItemPicture->setFile($fileName);
        $productItemPicture->setPosition(1);
        $productItemPicture->setSize(1000);
        $productItemPicture->setWidth(1200);
        $productItemPicture->setHeight(1000);

        $em->persist($productItemPicture);
        $em->flush();
        $em->clear();
        unset($productItemPicture);
        $i++;
    

感谢@Cerad 为我指明了这个方向。

【讨论】:

作为参考,我找到了这个主题,这不是完全相同的问题,但为这个问题带来了一些启示:***.com/questions/7431794/…【参考方案2】:

一个基本问题是:

// Replace
$pictureUrlRepository = new ProductItemPictureUrlRepository($em);

// With
$pictureUrlRepository = $em->getRepository('AppBundle:ProductItemPictureUrl');

实体管理器与其存储库之间存在复杂的关系。永远不要尝试直接实例化存储库。很多事情在幕后发生。很惊讶您的 findAll 甚至可以正常工作。

当然,您似乎也添加了学说事件侦听器?所以很难说问题出在哪里。如果存储库修复不起作用,请发布完整的堆栈跟踪。

您似乎还依赖于每个产品至少有四张图片,这有点危险。

=============================

如果问题已通过存储库建议解决,您的 cmets 并不清楚。但是在依赖 $pictures 的同时使用 $em->clear 也有点危险。当您清除经理时,不知道实体发生了什么。所以将它们移到循环之外:

for ($i = 0; $i < 4; ++$i) 
    $em->persist($productItemPicture);

$em->flush();
$em->clear();

是的,我知道您在处理大量项目时可能会达到内存限制。 ORM 不太擅长大批量作业。您可能需要下拉以使用 DBAL 连接对象。

【讨论】:

感谢您的关注。我理解您对存储库的“新”部分的担忧。我是 Symfony 的新手,我添加这个“新”部分只是因为在这里将代码发布到 ***。原因是,我在项目的其他部分发现了类似的代码,由其他程序员编写并且代码有效。所以,我自己使用的是这个代码 $doctrine->getRepository(ProductItemPictureUrl::class) 我希望和你发布的一样。 我没有使用事件监听器。在我的第二个代码示例中,我取消注册它们只是因为其他线程中的先前答案建议了这一点,以防存在一些内部侦听器。 在我的生产代码中,依赖图片的数量也是不正确的。此实际功能仅用于测试目的,以跟踪此错误。 我不知道如何获取此错误的堆栈跟踪,如何获取比简单的“通知:未定义索引”消息更多的信息。 感谢您的回答。存储库建议没有解决问题,它的工作原理相同。当我将 flush() 和 clear() 放在循环之外时,它工作正常。完全不使用 clear() 也是如此。有趣的是,当我运行我的原始代码时,在循环内使用 clear() 时,总是有 1 个项目插入到 DB 表中。 clear() 不会直接导致错误。我想只有在再次使用 $em 之后(在第一次 clear() 之后),它才会导致错误。因此,当我将 clear() 移到循环之外时,它不会触发任何错误,因为我的脚本在那里结束。

以上是关于Symfony3 / Doctrine2 中 $em->clear() 时出现未定义索引错误的主要内容,如果未能解决你的问题,请参考以下文章

Doctrine 2.5 意外的关联获取行为 [Symfony 3]

Symfony 3 - 登录时的防火墙监听器性能

Doctrine查询构建器

鉴别器图中缺少的实体

学说减慢了表现

使用多个时自动连接特定的 DBAL 连接