Problem/Motivation
When you use widget that allows to create new references (e.g. new tags in vocabulary), error like this will be returned on bulk edit:
message: "Drupal\\Core\\Entity\\EntityStorageException: SQLSTATE[23000]: Integrity\
\ constraint violation: 1062 Duplicate entry '<uuid>'\
\ for key 'taxonomy_term_data.taxonomy_term_field__uuid__value': INSERT INTO \"\
taxonomy_term_data\" (\"revision_id\", \"vid\", \"uuid\", \"langcode\") VALUES (:db_insert_placeholder_0,\
\ :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3);\
\ Array\n(\n [:db_insert_placeholder_0] => \n [:db_insert_placeholder_1] =>\
\ keywords\n [:db_insert_placeholder_2] => <uuid>\n\
\ [:db_insert_placeholder_3] => nl\n)\n in Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorage->save()\
\ (line 817 of /app/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php)."
Steps to reproduce
In my case I used Select2EntityReferenceWidget, but you can reproduce it with any entity reference field, where create option is allowed.
When we select a new term, the following code is executed in Select2EntityReferenceWidget::prepareFieldValues()
:
// We are not saving created entities, because that's part of
// Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::preSave().
$items[] = [
'entity' => $handler->createNewEntity($element['#target_type'], $element['#autocreate']['bundle'], $label, $element['#autocreate']['uid']),
];
This creates a new term entity with a UUID
but does not save it yet, so the TID
remains empty.
Now, consider the following scenario:
- Select at least two entities (note: this works fine if only one entity is selected for bulk update).
- Go to the bulk update form, enter a new term in the Search terms field, and Apply.
What happens? ViewsBulkOperationsActionBase::submitConfigurationForm()
is called and contains:
$form_state->cleanValues();
foreach ($form_state->getValues() as $key => $value) {
$this->configuration[$key] = $value;
}
This stores the unsaved term entity in the action configuration.
In BulkEditFormTrait:execute()
the term is retrieved from the configuration. Itβs still unsaved.
When saving the first entity, the term is saved to the database.
However, the $configuration is not updated with the saved entity data. So for the second entity we update in bulk, the same unsaved term (with UUID
but no ID
) is used again.
Drupal attempts to save it again, when updating second selected entity, but because the UUID
already exists in the database, an integrity constraint violation occurs.
Proposed resolution
Ensures new entity references are resolved prior to entity updates.
When updating multiple entities with a new entity reference (e.g., adding a new tag via an autocomplete field):
- The initial configuration might contain an unsaved entity object (with a UUID, but no ID)
- After the first entity in the batch is saved, this new reference is created.
The fix ensures that all subsequent entities in the batch correctly reference the newly persisted entity instead of the original, unsaved object.