Found a workaround for this:
Step 1: Add uuid to entity keys in annotation.
Step 2: Add custom storage handler in annotation.
Step 3: Create the custom storage handler class extending SqlContentEntityStorage with getCustomTableMapping overridden:
/**
* Use AddUuidTablemaaping to support adding uuid to base table.
*/
public function getCustomTableMapping(ContentEntityTypeInterface $entity_type, array $storage_definitions, $prefix = '') {
$prefix = $prefix ?: ($this->temporary ? 'tmp_' : '');
return AddUuidTableMapping::create($entity_type, $storage_definitions, $prefix);
}
Step 4: Create AddUuidTableMapping extending DefaultTableMapping and override create method.
public static function create(ContentEntityTypeInterface $entity_type, array $storage_definitions, $prefix = '') {
$table_mapping = new static($entity_type, $storage_definitions, $prefix);
$revisionable = $entity_type->isRevisionable();
$translatable = $entity_type->isTranslatable();
$id_key = $entity_type->getKey('id');
$revision_key = $entity_type->getKey('revision');
$bundle_key = $entity_type->getKey('bundle');
$uuid_key = $entity_type->getKey('uuid');
$langcode_key = $entity_type->getKey('langcode');
+ // The Magic, without this uuid will be added to dataTable if such exists.
+ if (array_key_exists('uuid', $storage_definitions)) {
+ $uuid_key = 'uuid';
+ }
+ // end Magic.
$shared_table_definitions = array_filter($storage_definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) {
return $table_mapping->allowsSharedTableStorage($definition);
});
$key_fields = array_values(
array_filter(
[$id_key, $revision_key, $bundle_key, $uuid_key, $langcode_key]
)
);
$all_fields = array_keys($shared_table_definitions);
$revisionable_fields = array_keys(array_filter($shared_table_definitions, function (FieldStorageDefinitionInterface $definition) {
return $definition->isRevisionable();
}));
// Make sure the key fields come first in the list of fields.
$all_fields = array_merge($key_fields, array_diff($all_fields, $key_fields));
...
}
Step 5: Create the field storage definition in post update hook:
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
/** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */
$field_storage_definition = BaseFieldDefinition::create('uuid')
->setLabel(new TranslatableMarkup('UUID'))
->setReadOnly(TRUE);
$definition_update_manager->installFieldStorageDefinition('uuid', $entity_type_id, 'my_custom_module', $field_storage_definition);
Step 6: Set uuid values for existing entities in baseTable:
$rows = $db_connection->select($entity_type_id, 'e')
->fields('e', ['id'])
->isNull('uuid')
->execute()
->fetchAll();
foreach ($rows as $row) {
$db_connection->update($entity_type_id)
->fields(['uuid' => \Drupal::service('uuid')->generate()])
->condition('id', $row->id)
->execute();
}
Step 7: Update entity type and field storage schema:
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$e = $definition_update_manager->getEntityType($entity_type_id);
$keys = $e->getKeys();
$keys['uuid'] = 'uuid';
$e->set('entity_keys', $keys);
$definition_update_manager->updateEntityType($e);
$field_storage_definition = $definition_update_manager->getFieldStorageDefinition('uuid', $entity_type_id);
$definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
This last step will update the entity type definition in db + make uuid field not_null in in baseTable.
Done.
Alternate solution is to use $definition_update_manager->updateFieldableEntityType, but will require overriding storage_schema handler(assuming there are existing entities) for the entity type as it forces not_null for entity keys by default.