API UPDATE add an item to an item set twice

Hi!
I am using ApiManager in a personal module to update items. However I randomly get this PDOException:

2017-07-21T10:40:28+00:00 ERR (3): exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2985-515' for key 'PRIMARY'' in /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:91
Stack trace:
#0 /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php(91): PDOStatement->execute(NULL)
#1 /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(1006): Doctrine\DBAL\Driver\PDOStatement->execute()
#2 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php(81): Doctrine\DBAL\Connection->executeUpdate('INSERT INTO ite...', Array, Array)
#3 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(400): Doctrine\ORM\Persisters\Collection\ManyToManyPersister->update(Object(Doctrine\ORM\PersistentCollection))
#4 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(356): Doctrine\ORM\UnitOfWork->commit(NULL)
#5 /omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(365): Doctrine\ORM\EntityManager->flush()
#6 /omeka-s/application/src/Api/Manager.php(233): Omeka\Api\Adapter\AbstractEntityAdapter->update(Object(Omeka\Api\Request))
#7 /omeka-s/application/src/Api/Manager.php(136): Omeka\Api\Manager->execute(Object(Omeka\Api\Request))
#8 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/ImportTrait.php(748): Omeka\Api\Manager->update('items', 2985, Array, Array, Array)
#9 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/ImportTrait.php(78): AlineImporter\Job\Import->tryMerge(Array, Array)
#10 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/Import.php(57): AlineImporter\Job\Import->importItemType(Array)
#11 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/Import.php(48): AlineImporter\Job\Import->import()
#12 /omeka-s/application/src/Job/Strategy/SynchronousStrategy.php(37): AlineImporter\Job\Import->perform()
#13 /omeka-s/application/src/Job/Dispatcher.php(105): Omeka\Job\Strategy\SynchronousStrategy->send(Object(Omeka\Entity\Job))
#14 /omeka-s/application/data/scripts/perform-job.php(43): Omeka\Job\Dispatcher->send(Object(Omeka\Entity\Job), Object(Omeka\Job\Strategy\SynchronousStrategy))
#15 {main}

Next exception 'Doctrine\DBAL\Driver\PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2985-515' for key 'PRIMARY'' in /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:93
Stack trace:
#0 /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(1006): Doctrine\DBAL\Driver\PDOStatement->execute()
#1 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php(81): Doctrine\DBAL\Connection->executeUpdate('INSERT INTO ite...', Array, Array)
#2 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(400): Doctrine\ORM\Persisters\Collection\ManyToManyPersister->update(Object(Doctrine\ORM\PersistentCollection))
#3 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(356): Doctrine\ORM\UnitOfWork->commit(NULL)
#4 /omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(365): Doctrine\ORM\EntityManager->flush()
#5 /omeka-s/application/src/Api/Manager.php(233): Omeka\Api\Adapter\AbstractEntityAdapter->update(Object(Omeka\Api\Request))
#6 /omeka-s/application/src/Api/Manager.php(136): Omeka\Api\Manager->execute(Object(Omeka\Api\Request))
#7 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/ImportTrait.php(748): Omeka\Api\Manager->update('items', 2985, Array, Array, Array)
#8 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/ImportTrait.php(78): AlineImporter\Job\Import->tryMerge(Array, Array)
#9 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/Import.php(57): AlineImporter\Job\Import->importItemType(Array)
#10 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/Import.php(48): AlineImporter\Job\Import->import()
#11 /omeka-s/application/src/Job/Strategy/SynchronousStrategy.php(37): AlineImporter\Job\Import->perform()
#12 /omeka-s/application/src/Job/Dispatcher.php(105): Omeka\Job\Strategy\SynchronousStrategy->send(Object(Omeka\Entity\Job))
#13 /omeka-s/application/data/scripts/perform-job.php(43): Omeka\Job\Dispatcher->send(Object(Omeka\Entity\Job), Object(Omeka\Job\Strategy\SynchronousStrategy))
#14 {main}

Next exception 'Doctrine\DBAL\Exception\UniqueConstraintViolationException' with message 'An exception occurred while executing 'INSERT INTO item_item_set (item_id, item_set_id) VALUES (?, ?)' with params [2985, 515]:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2985-515' for key 'PRIMARY'' in /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:66
Stack trace:
#0 /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php(128): Doctrine\DBAL\Driver\AbstractMySQLDriver->convertException('An exception oc...', Object(Doctrine\DBAL\Driver\PDOException))
#1 /omeka-s/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(1015): Doctrine\DBAL\DBALException::driverExceptionDuringQuery(Object(Doctrine\DBAL\Driver\PDOMySql\Driver), Object(Doctrine\DBAL\Driver\PDOException), 'INSERT INTO ite...', Array)
#2 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php(81): Doctrine\DBAL\Connection->executeUpdate('INSERT INTO ite...', Array, Array)
#3 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(400): Doctrine\ORM\Persisters\Collection\ManyToManyPersister->update(Object(Doctrine\ORM\PersistentCollection))
#4 /omeka-s/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(356): Doctrine\ORM\UnitOfWork->commit(NULL)
#5 /omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(365): Doctrine\ORM\EntityManager->flush()
#6 /omeka-s/application/src/Api/Manager.php(233): Omeka\Api\Adapter\AbstractEntityAdapter->update(Object(Omeka\Api\Request))
#7 /omeka-s/application/src/Api/Manager.php(136): Omeka\Api\Manager->execute(Object(Omeka\Api\Request))
#8 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/ImportTrait.php(748): Omeka\Api\Manager->update('items', 2985, Array, Array, Array)
#9 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/ImportTrait.php(78): AlineImporter\Job\Import->tryMerge(Array, Array)
#10 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/Import.php(57): AlineImporter\Job\Import->importItemType(Array)
#11 /omeka-s/modules/AlineImporter/src/AlineImporter/Job/Import.php(48): AlineImporter\Job\Import->import()
#12 /omeka-s/application/src/Job/Strategy/SynchronousStrategy.php(37): AlineImporter\Job\Import->perform()
#13 /omeka-s/application/src/Job/Dispatcher.php(105): Omeka\Job\Strategy\SynchronousStrategy->send(Object(Omeka\Entity\Job))
#14 /omeka-s/application/data/scripts/perform-job.php(43): Omeka\Job\Dispatcher->send(Object(Omeka\Entity\Job), Object(Omeka\Job\Strategy\SynchronousStrategy))
#15 {main}

If I launch my script a second time it usually works or fail later (Update request is in a while loop).

Probably a synchronisation issue because the same code sometimes works and sometimes fails.

Do you know where does this problem come from?
And how can i fix this?

I don’t think we’ve seen this ourselves at all, nor do I remember it in any reports.

Is it possible that your import code could be doing something like (intermittently) including the same item set twice in the update data? The partial update is tolerant of a request to “append” something that’s already in the persistent data, but it’s probably not tolerant of the update request itself containing a duplicate.

I don’t think it is possible. This is my code:

$cleanedData = [];

if(!isset($schema['sameSet']) || !$schema['sameSet']) 
	$cleanedData['o:item_set']=$data['o:item_set'];

if(!empty($schema['addProperties'])) 
	foreach ($schema['addProperties'] as $term)
		$cleanedData[$term]=$data[$term];

if(!empty($cleanedData))
	$this->api->update('items', $item->id(), $cleanedData, [],
			['isPartial'=>true, 'collectionAction' => 'append'] );

And $schema['addProperties'] has only two possible values: ['locn:postName'] or ['locn:address'].