Problem/Motivation

After updating to the last 8.x-1.x-dev version, I'm getting the following message in Status report:

Mismatched entity and/or field definitions
The following changes were detected in the entity type and field definitions.
Contact
The First Name field needs to be updated.
The Middle Name field needs to be updated.
The Last Name field needs to be updated.

I have tried to use the Devel Entity Updates module to fix it, but then I'm getting:

In SqlContentEntityStorageSchema.php line 1887:
The SQL storage cannot change the schema for an existing field (first_name in redhen_contact entity) with data.

Any hint about a better way to fix it will be welcome.

Issue fork redhen-3163820

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sahaj created an issue. See original summary.

gcb’s picture

Assigned: Unassigned » gcb
seanr’s picture

I ran into this today. Any advice would be greatly appreciated. This occurred as part of a D9 upgrade, but I'm not entirely sure where the update flopped (I may have missed it in updating everything to latest D8) - my suspicion is that redhen.install is missing something.

chertzog’s picture

Having just updated 5 redhen installs to D9 over the past month, this is still an issue. That being said, it hasnt stopped me or presented any problems just so far, so it has been a pretty low priority item.

I'm hoping to find some time in the next couple weeks to see where thee breakdown is and work up a patch.

seanr’s picture

It seems to me there was a missed/deleted update hook in one of the various version upgrades to this module?

seanr’s picture

seanr’s picture

[message deleted]

Ugh, that didn't work either (I forgot I'd deleted the contacts in my local test environment). Stuck at square one. How the hell do I get a working update to fix these f***ing fields?!?

seanr’s picture

This finally worked:

/**
 * Update name fields in RedHen Contact Entity Schema.
 */
function redhen_contact_update_8001() {
  $config = \Drupal::config('redhen_contact.settings');
  $required_names = $config->get('required_properties');
  $entity_type_manager = \Drupal::entityTypeManager();
  $bundle_of = 'redhen_contact';

  $storage = $entity_type_manager->getStorage($bundle_of);
  $bundle_definition = $entity_type_manager->getDefinition($bundle_of);
  // Sometimes the primary key isn't 'id'. e.g. 'eid' or 'item_id'.
  $id_key = $bundle_definition->getKey('id');
  // If there is no data table defined then use the base table.
  $table_name = $storage->getDataTable() ?: $storage->getBaseTable();
  $database = \Drupal::database();
  $definition_manager = \Drupal::entityDefinitionUpdateManager();

  $fields = [
    'first_name' => 'First Name',
    'middle_name' => 'Last Name',
    'last_name' => 'Middle Name',
  ];
  $field_keys = array_keys($fields);
  array_unshift($field_keys, $id_key);

  // Store the existing values.
  $name_values = $database->select($table_name)
    ->fields($table_name, $field_keys)
    ->execute()
    ->fetchAllAssoc($id_key, PDO::FETCH_ASSOC);

  // Clear out the values.
  $database->update($table_name)
    ->fields(array_fill_keys(array_keys($fields), NULL))
    ->execute();

  // Uninstall the fields.
  foreach ($fields as $field_name => $field_label) {
    $field_storage_definition = $definition_manager->getFieldStorageDefinition($field_name, $bundle_of);
    $definition_manager->uninstallFieldStorageDefinition($field_storage_definition);

    // Create a new field definition.
    $new_field = BaseFieldDefinition::create('string')
      ->setLabel(t($field_label))
      ->setSettings([
        'max_length' => 255,
        'text_processing' => 0,
      ])
      ->setDefaultValue('')
      ->setDisplayOptions('form', [
        'type' => 'string_textfield',
        'weight' => -10,
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
      ->setRequired($required_names[$field_name])
      ->setRevisionable(TRUE);

    // Install the new definitions.
    $definition_manager->installFieldStorageDefinition($field_name, $bundle_of, $bundle_of, $new_field);
  }

  // Restore the values.
  foreach ($name_values as $id => $value) {
    $field_values = [];
    foreach (array_keys($fields) as $key) {
      $field_values[$key] = $value[$key];
    }
    $database->update($table_name)
      ->fields($field_values)
      ->condition($id_key, $id)
      ->execute();
  }
}
gcb’s picture

Thanks, this is really handy!

The reason we didn't have a hook update was two factors: one was it seemed hard, as you have discovered, and the other is that the change was made back in alpha and... ya know, alpha isn't stable anyway. But this is really helpful.

I'm mildly concerned about timeouts on large databases, though, and I'm also concerned about running this on sites that have already made the change in some other way. For this reason, I think it would be better as a drush command.

chertzog’s picture

Initial testing of #8 does in fact resolve the errors, but now none of my contacts have names. My initial guess is that its due to the number of records. i've got ~20k contacts.

  • gcb committed 12f430b on 8.x-1.x authored by seanr
    Issue #3163820 by seanr, gcb: Mismatched entity and/or field definitions...
gcb’s picture

Status: Active » Fixed

Ok, drush command added. It'll be in the next release.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

seanr’s picture

@gcb - I think this needs to be reopened. It turns out it's not updating the fields in the redhen_contacts_revision table.

seanr’s picture

Adding this at the end solved that:

    // Values need to be reinserted into revisions as well.
    $database->update($table_name . '_revision')
      ->fields($field_values)
      ->condition($id_key, $id)
      ->execute();
chertzog’s picture

+1 for re-opening this and adding #15 to the end of the update hook

gcb’s picture

Status: Closed (fixed) » Needs work

Harlor made their first commit to this issue’s fork.

Harlor’s picture

Assigned: gcb » Unassigned
Status: Needs work » Needs review

I think the main reason the message appeared in the status report is that the maxlength was changed in https://git.drupalcode.org/project/redhen/-/commit/2ed52ef4c775e0a18c111... without updating existing DBs.

Usually the definition_update_manager makes all the DB changes and no explicit DB commands are needed. AFAIK The typical place for these updates is a post_update hook - So I moved the script from the drush cmd too the hook and removed the manual DB actions.

tobiasb’s picture

Status: Needs review » Reviewed & tested by the community

@Harlor

Thx. proper solution for such updates.

  • Harlor committed 7033c419 on 8.x-1.x
    Issue #3163820 Remove obsolete redhen_contact drush command
    

  • Harlor committed 7d18f456 on 8.x-1.x
    Issue #3163820 update redhen_contact entity via post_update hook
    
gcb’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.