在 Doctrine2/Symfony2 中的重复条目上插入忽略
Posted
技术标签:
【中文标题】在 Doctrine2/Symfony2 中的重复条目上插入忽略【英文标题】:insert ignore on duplicate entries in Doctrine2/Symfony2 【发布时间】:2012-03-14 09:58:12 【问题描述】:如何使用 Doctrine2 忽略重复条目?
错误示例:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'symfony' for key 'UNIQ_389B783389B783'
【问题讨论】:
你可以做 propel 做的事情:创建一个像 findByKeyOrCreate() 这样的方法,如果有则返回一个现有实体,如果没有则创建一个新实体。 如果不需要,请从该字段中删除@Unique
索引。
当您尝试保存非唯一条目时,您期望从中得到什么结果?
【参考方案1】:
这是 Doctrine 的麻烦之一,无法执行 INSERT/UPDATE Ignore,有一些解决方法,例如创建一个方法来检查该行是否存在,如果存在则跳过它。
您可以捕获异常,这样您的脚本就不会以异常结束。但是,实体管理器将被关闭,您将无法再使用它。不过,您仍然可以使用 PDO,并且可以在数据库中插入一条记录,指示您的批处理失败,因为 X
并且需要重新启动它(我通常这样做)。
如果以上选项都不适合您,最终我会编写原始 SQL 来进行批处理,而我根本不使用 Doctrine,它最终会更快,并且执行 INSERT/UPDATE Ignore 的能力使它成为可能不费吹灰之力。
【讨论】:
如果你不介意覆盖项目,你可以使用 ***.com/a/15838232/1454173 中的合并(已弃用,将在 Doctrine ORM 3.0 中删除)【参考方案2】:在 Symfony 3 中,您可以通过在捕获 UniqueConstraintViolationException
异常后调用 Doctrine
对象的 resetManager()
方法来重置管理器并继续使用它。
这是一个例子:
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();
【讨论】:
不错的分享! (即resetManager()) 我会对这种类型的最新答案感兴趣。 resetManager() 现已弃用。 如果你使用 symfony 3/4 使用composer require symfony/proxy-manager-bridge
【参考方案3】:
您总是可以捕获异常然后忽略它。请注意,当实体管理器引发异常时,在该请求期间不能再使用实体管理器。
【讨论】:
【参考方案4】:您还可以在实际插入之前检查重复项。我有一个类似的问题并在这里回答: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();
【讨论】:
这仅在您将重复项保存在一个线程中时有用,这是更简单的情况。问题通常是两个线程(两个服务器请求)试图同时创建相同的东西。以上是关于在 Doctrine2/Symfony2 中的重复条目上插入忽略的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Doctrine2 (Symfony2) 中按案例排序