Пропускать сущности во время очистки, когда они дублируют - PullRequest
6 голосов
/ 17 апреля 2011

Я немного играю с 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 обновляется, и некоторые элементы новые, а некоторые нет. Есть ли способ сказать менеджеру объектов пропустить дубликаты файлов и просто вставить новые?

Какой лучший способ сделать это?

Спасибо за помощь. Пожалуйста, оставьте комментарий, если что-то неясно

Edit:

то, что работает для меня, делает что-то вроде этого:

$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, который проверяет, есть ли заголовок в моей базе данных.

это ужасно. это 2 запроса к базе данных для каждого элемента. это завершает около 85 запросов к базе данных для этого действия.

Ответы [ 2 ]

1 голос
/ 20 апреля 2011

Как насчет извлечения всех текущих заголовков в массив сначала и проверки вставки заголовка по текущим заголовкам в этом массиве

$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 (), чтобы сделать запрос для всехте элементы с названиями, которые вы пытаетесь вставить.Таким образом, максимальная сумма $ существующей плитки, которую вы вернете, будет соответствовать размеру вашего списка вставленных данных.Тогда вы можете выполнить свои проверки, как указано выше.

// getCurrentTitles() - $newTitles is array of all new titles you want to insert
return $qb->select('title')
   ->from('Table', 't')
   ->in('t.title = ', $newTitles)
   ->getArrayResult();
0 голосов
/ 27 апреля 2011

Если вы используете сущность, которая, возможно, уже существует в менеджере, вы должны объединить ее.

Вот что я хотел бы сделать (еще не проверял):

$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();
...