Вставить игнорировать дубликаты записей в Doctrine2/Symfony2

Как игнорировать дубликаты записей с помощью Doctrine2?

Пример ошибки:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'symfony' for key 'UNIQ_389B783389B783'

Ответ 1

В одной из неприятностей Doctrine невозможно выполнить INSERT/UPDATE Ignore, есть обходное решение, например, создание методов, которые проверяют, существует ли строка, и если это так, просто пропустите ее.

Вы можете поймать исключение, так что ваш script не закончится исключением. Однако диспетчер объектов будет закрыт, и вы больше не сможете его использовать. Тем не менее, вы все равно можете использовать PDO, и вы можете вставить запись в базу данных, указывающую на то, что ваша партия завершилась неудачно, поскольку X и ее необходимо перезапустить (что я обычно делаю).

Если ни одна из вышеперечисленных опций не работает для вас, в конечном итоге я в конечном итоге пишу raw SQL для пакетной обработки, и я вообще не использую Doctrine, она заканчивается быстрее и способность делать INSERT/UPDATE Ignore делает это без проблем.

Ответ 2

В Symfony 3 вы можете reset manager и продолжить работу с ним, вызвав метод resetManager() объекта Doctrine после исключения UniqueConstraintViolationException.

Вот пример:

try {
  $em = $this->getDoctrine()->getManager();
  $entity = Product::create()
    ->setTitle('Some title')
    ->setUrl('http://google.com');
  $em->persist($entity);
  $em->flush();
}
catch (UniqueConstraintViolationException $e) {
  $this->getDoctrine()->resetManager();
}

Ответ 3

Вы всегда можете поймать исключение, а затем проигнорировать его. Просто имейте в виду, что когда администратор сущности создает исключение, диспетчер объектов больше не может использоваться во время этого запроса.

Ответ 4

Вы также можете проверить наличие дубликатов перед фактической вставкой. У меня была похожая проблема, и я ответил на нее здесь: doctrine/symfony 4 - избегайте повторяющихся записей при сохранении дочерних сущностей

protected function removeDuplicates($insertions) {
    foreach ($insertions as $key => $insertion) {
        $shortClassName = (new ReflectionClass($insertion))->getShortName();
        // TODO: The search can be heavily optimized
        foreach ($insertions as $possibleDupeKey => $possibleDupeInsertion) {
            $shortDupeClassName = (new ReflectionClass($insertion))->getShortName();
            // TODO: Treat case when unique is on a field not called 'id'
            if ($shortClassName === $shortDupeClassName && $insertion->getId() === $possibleDupeInsertion->getId() && $key !== $possibleDupeKey) {
                $this->em->remove($possibleDupeInsertion);
            }
        }
    }
}

protected function saveStuff($order) {
    $this->em->persist($order);
    $this->removeDuplicates($this->em->getUnitOfWork()->getScheduledEntityInsertions());
    $this->em->flush();
}