Игнорировать дубликаты при использовании INSERT в базе данных с Symfony и Doctrine

У меня есть таблица

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 

И triing, чтобы сохранить объект с Доктриной:

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

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

Как сделать INSERT IGNORE в таблицу с symfony?

 $sbTagsArticles->isNew(); 

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

Thnx.

 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) статьи / тега существовала, добавьте уникальный индекс в (article_id, tag_id) . Это должно генерировать ошибку mysql, которая, в свою очередь, генерирует исключение доктрины, которое вы можете поймать. Существует не игнорировать флаг для сохранения … Возможно, вы сможете использовать один из них, работающий на более низком уровне DBAL (Doctrine_Query, Doctrine_Connection и т. Д.), Но не направляемый с уровня ORM.

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

Также почему вы используете механизм хранения 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 

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

 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 */ } 

Вы можете расширить объект 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