Problem/Motivation

Content entities that use SQL storage (which are most of them in core and in contrib) have a table schema that can involve up to 4 tables for base fields:

- base table
- data table
- revision table
- revision data table

Whether all 4 tables exist depends on whether the entity type is translatable or revisionable, and base fields go in different tables (or more than one table!) based on their own translatability or revisionability.

This is fairly complicated to understand!

There does not appear to be a single place that explains this all clearly in the documentation.

The best explanation that I can find is this sequence of inline comments in DefaultTableMapping:

    if (!$revisionable && !$translatable) {
      // The base layout stores all the base field values in the base table.
      $table_mapping->setFieldNames($table_mapping->baseTable, $all_fields);
    }
    elseif ($revisionable && !$translatable) {
      // The revisionable layout stores all the base field values in the base
      // table, except for revision metadata fields. Revisionable fields
      // denormalized in the base table but also stored in the revision table
      // together with the entity ID and the revision ID as identifiers.
      $table_mapping->setFieldNames($table_mapping->baseTable, array_diff($all_fields, $revision_metadata_fields));
      $revision_key_fields = [$id_key, $revision_key];
      $table_mapping->setFieldNames($table_mapping->revisionTable, array_merge($revision_key_fields, $revisionable_fields));
    }
    elseif (!$revisionable && $translatable) {
      // Multilingual layouts store key field values in the base table. The
      // other base field values are stored in the data table, no matter
      // whether they are translatable or not. The data table holds also a
      // denormalized copy of the bundle field value to allow for more
      // performant queries. This means that only the UUID is not stored on
      // the data table.
      $table_mapping
        ->setFieldNames($table_mapping->baseTable, $key_fields)
        ->setFieldNames($table_mapping->dataTable, array_values(array_diff($all_fields, [$uuid_key])));
    }
    elseif ($revisionable && $translatable) {
      // The revisionable multilingual layout stores key field values in the
      // base table and the revision table holds the entity ID, revision ID and
      // langcode ID along with revision metadata. The revision data table holds
      // data field values for all the revisionable fields and the data table
      // holds the data field values for all non-revisionable fields. The data
      // field values of revisionable fields are denormalized in the data
      // table, as well.

      $table_mapping->setFieldNames($table_mapping->baseTable, $key_fields);

      // Like in the multilingual, non-revisionable case the UUID is not
      // in the data table. Additionally, do not store revision metadata
      // fields in the data table.

but there are snippets of useful information elsewhere too, e.g.:

      // Only the data table follows the entity language key, dedicated field
      // tables have a hard-coded 'langcode' column.
      // Since a field may be stored in more than one table, we inspect tables
      // in order of relevance: the data table if present is the main place
      // where field data is stored, otherwise the base table is responsible for
      // storing field data. Revision metadata is an exception as it's stored
      // only in the revision table.
        // Find fields that are not revisioned or entity keys. Data fields have
        // the same value regardless of entity revision.

Steps to reproduce

Proposed resolution

Add an overview to the class docs of DefaultTableMapping.

Add @see references in other places.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Comments

joachim created an issue. See original summary.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

acbramley’s picture

Category: Bug report » Task
Issue tags: +Bug Smash Initiative

This was triaged as part of BSI. I do not think this is a bug, but rather a documentation task.

joachim’s picture

Category: Task » Bug report

It's documentation, but missing documentation is a bug.

smustgrave’s picture

Came up again but hasn't been much change since. Does seem like a task to me also though.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.