当实体为重复时,在刷新时跳过实体


Skip Entities while flushing when they are a Duplicate

我正在使用Symfony2和Doctrine2。

我有一个具有唯一标题的实体,例如:

class listItem
{
    /**
     * @orm:Id
     * @orm:Column(type="integer")
     * @orm:GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @orm:Column(type="string", length="255", unique="true")
     * @assert:NotBlank()
     */
    protected $title;

现在我正在获取json和更新我的数据库与这些项目:

$em = $this->get('doctrine.orm.entity_manager');
        
foreach($json->value->items as $item) {
    $listItem = new ListItem();
    $listItem->setTitle($item->title);
    $em->persist($listItem);
}
$em->flush();

第一次工作很好。但第二次我得到一个sql错误(当然):Integrity constraint violation: 1062 Duplicate entry

有时我的json文件得到更新,有些项目是新的,有些不是。是否有一种方法告诉实体管理器跳过重复的文件,只是插入新的?

最好的方法是什么?

谢谢你的帮助。如果有不清楚的地方,请留下评论

编辑:

对我来说有效的是这样做:

$uniqueness = $em->getRepository('ListItem')->checkUniqueness($item->title);
    if(false == $uniqueness) {
        continue;
    }
    $listItem = new ListItem();
    $listItem->setTitle($item->title);
    $em->persist($listItem);
    $em->flush();
}

checkUniqueness是我的listtitem Repo中的一个方法,检查标题是否已经在我的数据库中。

这是可怕的。这是针对每个项目的2个数据库查询。这个操作最终会产生85个数据库查询。

如何首先将所有当前标题检索到数组中,并根据该数组中的当前标题检查插入标题

$existingTitles = $em->getRepository('ListItem')->getCurrentTitles();
foreach($json->value->items as $item) {
  if (!in_array($item->title, $existingTitles)) {
    $listItem = new ListItem();
    $listItem->setTitle($item->title);
    $em->persist($listItem);
  }
}
$em->flush();

getCurrentTitles()需要添加到listtitem Repo中,以简单地返回一个标题数组。

这只需要一个额外的DB查询,但是在数组中保存当前标题会花费更多的内存。如果listtitem的数据集非常大,那么这种方法可能会出现问题。

如果每次想要插入的条目数量不是太大,可以修改getCurrentTitles()函数来查询所有带有您想要插入的标题的条目。这样,您将返回的$existingTiles的最大值将是插入数据列表的大小。然后,您可以按上述方式进行检查。

// getCurrentTitles() - $newTitles is array of all new titles you want to insert
return $qb->select('title')
   ->from('Table', 't')
   ->in('t.title = ', $newTitles)
   ->getArrayResult();

如果您使用的实体可能已经存在于管理器中,则必须合并它。

下面是我要做的(还没有测试):
$repository = $this->get('doctrine.orm.entity_manager');
foreach($json->value->items as $item) {
    $listItem = new ListItem();
    $listItem->setTitle($item->title);
    $em->merge($listItem); // return a managed entity
    // no need to persist as long as the entity is now managed
}
$em->flush();