6

我正在玩一点 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是我的 ListItem Repo 中的一种方法,用于检查标题是否已经在我的数据库中。

那太糟了。这是每个项目的 2 个数据库查询。这最终会为此操作产生大约 85 个数据库查询。

4

2 回答 2

1

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

$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() 添加到 ListItem Repo 以简单地返回标题数组。

这只需要一个额外的数据库查询,但会花费更多的内存来保存数组中的当前标题。如果您的 ListItem 数据集非常大,则此方法可能存在问题。

如果您每次要插入的项目数不是太大,您可以修改 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();
于 2011-04-20T13:18:22.907 回答
0

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

这是我要做的(尚未测试):

$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();
于 2011-04-27T11:30:58.923 回答