如何使用Doctrine2忽略重复的条目?
错误示例:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'symfony' for key 'UNIQ_389B783389B783'
答案 0 :(得分:14)
在 Symfony 3 中,您可以重置管理员,并在捕获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();
}
答案 1 :(得分:13)
这是Doctrine的一个麻烦,它无法进行INSERT / UPDATE忽略,有一些解决方法,比如创建一个检查行是否存在的方法,如果确实存在,那么就跳过它。
您可以捕获异常,以便您的脚本不会以异常结束。但是,实体经理将被关闭,您将无法再使用它。您仍然可以使用PDO,但是您可以在数据库中插入一条记录,指示您的批处理失败,因为X
并且需要重新启动(这是我通常所做的)。
如果上面的选项都不适合你,最终我最终编写原始SQL来进行批处理,而我根本不使用Doctrine,它最终会更快,并且能够执行INSERT / UPDATE忽略让它变得毫无疑问。
答案 2 :(得分:11)
您始终可以捕获异常,然后忽略它。请注意,当实体管理器引发异常时,在该请求期间不能再使用实体管理器。
答案 3 :(得分:0)
您还可以在实际插入之前检查重复项。我有一个类似的问题,并在这里回答:doctrine/symfony 4 - avoid duplicate entry when persisting child entities
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();
}