【问题标题】:Doctrine Batch insert - entity manager clearDoctrine Batch insert - 实体管理器清除
【发布时间】:2015-11-07 20:37:47
【问题描述】:

我想通过批处理向数据库插入 10 000 行。 在第一步中,我需要从数据库中选择一些对象,然后对这些对象进行交互,并为每个对象将另一个对象保存到数据库中。 这是代码示例:

 $em = $this->getDoctrine()->getManager();
    $products = $em->getRepository('MyBundle:Product')->findAll(); // return 10 000 products
    $category = $em->getRepository('MyBundle:Category')->find(1);
    $batchsize = 100;
    foreach ($products as $i => $product) {
        $entity = new TestEntity();
        $entity->setCategory($category);
        $entity->setProduct($product); // MyEntity And Product is OneToOne Mapping with foreign key in MyEntity
        $em->persist($entity);
        if ($i % $batchsize === 0) {
            $em->flush();
            $em->clear();
        }
    }
    $em->flush();
    $em->clear();

它返回此错误:

A new entity was found through the relationship 'Handel\GeneratorBundle\Entity\GenAdgroup#product' that was not configured to cascade persist operations for entity

我认为问题出在clear(),它删除了内存中的所有对象,包括 $products 和 $category

如果我在关联中使用cascade={"persist"},则学说在数据库中插入新的类别行。

经过一些尝试,我犯了一些肮脏的实体错误。

我是不是做错了什么?这项工作的解决方案和最佳实践是什么? 非常感谢回答

【问题讨论】:

    标签: php mysql symfony doctrine-orm


    【解决方案1】:

    解决方案只是清除那些正在更改/创建的对象。那些不变的应该留在EntityManager中。

    像这样

    $em->clear(TestEntity::class);
    $em->clear(...);
    

    如果您在没有参数的情况下清除它,它将分离实体管理器下当前的所有对象。这意味着如果您尝试重用它们,它将在您得到时抛出错误。例如,唯一的字段将被复制并引发该错误。

    【讨论】:

      【解决方案2】:

      调用后

      $em->clear();
      

      类别对象变为非持久化。 您可以尝试在其上调用 $em->merge($category) 方法。但可能最有保证的方法是再次获取它。

          if ($i % $batchsize === 0) {
              $em->flush();
              $em->clear();
              $category = $em->getRepository('MyBundle:Category')->find(1);
          }
      

      【讨论】:

      • 但我不想保留类别,我已经存储了 id,我只读取它并设置为外键。
      • Persist 不会像您预期的那样工作。合并可能,但最好的选择是 $category = $em->getRepository('MyBundle:Category')->find(1);
      • 如果您不需要完整的实体,请考虑使用 getReference 而不是 find。
      • 您可以在此处阅读,当您从数据库中获取对象时 - 它会自动进行管理。 symfony.com/doc/current/book/doctrine.html#updating-an-object 通过像这样($em->persist($category) 持久化它,它不会作为新实体(具有新 ID)添加到数据库中。我已经编辑了答案,因为它确实是最好的保证拥有托管 Category 对象的方法是简单地再次获取它。
      • 差不多。但是你需要有 $category = $em... 否则将使用原来的现在非托管对象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      • 1970-01-01
      • 2015-07-30
      • 2011-10-04
      • 1970-01-01
      • 2015-07-30
      相关资源
      最近更新 更多