Игнорировать дубликаты при использовании INSERT в базе данных с Symfony и Doctrine - PullRequest
6 голосов
/ 16 февраля 2010

у меня есть стол

CREATE TABLE `sob_tags_articles` (
  `tag_id` int(11) NOT NULL,
  `article_id` int(11) NOT NULL,
  `id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=112

И попытка спасти объект с помощью Доктрины:

$sbTagsArticles = new SobTagsArticles();
$sbTagsArticles->article_id = $pubId;
$sbTagsArticles->tag_id = $tagId;
$sbTagsArticles->save();

Но если запись существует с тем же $ pubId и $ tagId, новая запись будет вставлена ​​с новым PK.

Как сделать INSERT IGNORE в таблице с помощью symfony?

$sbTagsArticles->isNew();

возвращает 1.

Thnx.

Ответы [ 3 ]

13 голосов
/ 16 февраля 2010
try
{
    $record->save();
}
catch(Doctrine_Exception $e)
{
    if($e->getErrorCode() !== $duplicateKeyCode)
    {
        /**
         * if its not the error code for a duplicate key 
         * value then rethrow the exception
         */
        throw $e;
    }

    /**
     * you might want to fetch the real record here instead 
     * so yure working with the persisted copy
     */
}

Вы должны убедиться, что одна и та же запись не существует на стороне приложения, а не на стороне SQL. Если вы не хотите, чтобы существовала одна и та же комбинация статьи / тега, добавьте уникальный индекс к (article_id, tag_id). Это должно привести к ошибке mysql, которая, в свою очередь, сгенерирует исключение доктрины, которое вы можете перехватить. Для сохранений нет флага игнорирования ... Возможно, вы сможете использовать один из них, работающий на более низком уровне DBAL (Doctrine_Query, Doctrine_Connection и т. Д.), Но не напрямую со слоя ORM.

Doctrine_Record::isNew() всегда будет возвращать true, если вы создали экземпляр записи, а не извлекали ее из базы данных, в противном случае у нее нет способа узнать, является ли запись новой или нет.

Кроме того, почему вы используете механизм хранения MyISAM? Я почти уверен, что это на самом деле приведет к дополнительным издержкам при использовании Doctrine, поскольку тогда ему нужно эмулировать ограничения на стороне php. Обычно ваша схема будет выглядеть примерно так:

CREATE TABLE `sob_tags_articles` (
  `tag_id` int(11) NOT NULL,
  `article_id` int(11) NOT NULL,
  `id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`id`),
  CONSTRAINT `some_unique_constraint_name_1`
      FOREIGN KEY `article_id`
      REFERENCES `article` (`id`)
      ON DELETE CASCADE,
  CONSTRAINT `some_unique_constraint_name_2`
      FOREIGN KEY `tag_id`
      REFERENCES `tag` (`id`)
      ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=112
6 голосов
/ 20 июля 2012

Это фактический код, который будет использоваться

try
{
    $record->save();
}
catch(Doctrine_Connection_Exception $e)
{
    if($e->getPortableCode() != Doctrine::ERR_ALREADY_EXISTS)
    {
        /**
         * if its not the error code for a duplicate key 
         * value then rethrow the exception
         */
        throw $e;
    }
    /**
     * you might want to fetch the real record here instead 
     * so yure working with the persisted copy
     */
}
0 голосов
/ 16 февраля 2010

Вы можете расширить объект SobTagsArticles с помощью нового метода сохранения и проверить, существует ли запись:

public function exists() {
  $q = Doctrine_Query::create()
    ->from('sobtagsarticles ta')
    ->where('ta.tag_id = ? and ta.article_id = ?', array($this->getTagId(), $this->getArticleId()));

  if (!$result = $q->execute())
  {
    parent::save();
  }
}

Таким образом, объект будет сохранен, только если он не существует.

Вы также можете установить уникальный индекс для вашей таблицы следующим образом:

UNIQUE INDEX `sb_tags_articles_unique` (`tag_id` ASC, `article_id` ASC)

Ваша схема будет выглядеть так:

CREATE TABLE `sob_tags_articles` (
  `tag_id` int(11) NOT NULL,
  `article_id` int(11) NOT NULL,
  `id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`id`),
  UNIQUE INDEX `sb_tags_articles_unique` (`tag_id` ASC, `article_id` ASC),
  CONSTRAINT `some_unique_constraint_name_1`
      FOREIGN KEY `article_id`
      REFERENCES `article` (`id`)
      ON DELETE CASCADE,
  CONSTRAINT `some_unique_constraint_name_2`
      FOREIGN KEY `tag_id`
      REFERENCES `tag` (`id`)
      ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=112
...