Examples:

The primary key for group memberships is uid + nid, that is, a key built from two columns. Unless, someone is allowed to join a group twice..
See #1006348-5: Make group memberships a fieldable entity.

The primary key for languages would/could be the language code. Not sure why someone would make that an entity, though ..

Have a look at ORMs like Doctrine, they usually do support all kinds of primary keys.

As far as I understand, D7 entities must always have a numeric id as the primary key.

Of course, multi-column primary keys make a few things more difficult: They can't easily be used as array keys, etc. So a lot of code would become more ugly and heavy. Is it worth the trouble? Maybe.

Alternative: A synthetic one-column key composed from a two-column key, with things like serialize() or binary zipper.

Comments

jplarose’s picture

I would also like proper support in entities for multi-column primary keys and non-numeric primary keys.

In the meantime, for those who need to create entities right now with unsupported primary keys, you can create a new column, make it the primary key, and set the column(s) that ought to be the PK as unique.
e.g. change from :

$schema['membership'] = array(
  'fields' => array(
    'uid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
    'gid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
  ),
  'primary key' => array('uid', 'gid'),
);

to:

$schema['membership'] = array(
  'fields' => array(
    'gmid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
    'uid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
    'gid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
  ),
  'primary key' => array('gmid'),
  'unique keys' => array(
    'group_member' => array('uid', 'gid'),
  ),
);

It's kludgey, but until support for a wider range of primary keys is implemented, this will may have to do.

SilviuChingaru’s picture

Why 'group_member', shouldn't be 'gmid'? Can you explain a little how it's work? In the hook_entity_info() we specify as id the gmid?

$schema['membership'] = array(
  'fields' => array(
    'gmid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
    'uid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
    'gid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
  ),
  'primary key' => array('gmid'),
  'unique keys' => array(
    // Why 'group_member', shouldn't be 'gmid'?
    'group_member' => array('uid', 'gid'),
  ),
);

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Gogowitsch’s picture

Issue summary: View changes

To have an entity table in the database have a multi-column index, you need to add your own schema class to the entity annotation:

 * @ContentEntityType(
 *   id = "uid_nid",
 *   label = @Translation("User node entity"),
 *   handlers = {
 *     "storage_schema" = "Drupal\your_uid_nid_entity_module\UserNodeSchema",
...

Your own schema class should extend SqlContentEntityStorageSchema and implement getSharedTableFieldSchema. E.g. this adds a unique index to a "UserNode" entity

class UserNodeSchema extends SqlContentEntityStorageSchema {

  /**
   * {@inheritdoc}
   */
  protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) {
    $aSchema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
    if ($table_name === 'uid_nid_field_data' && $storage_definition->getName() === 'item')
      $aSchema['unique keys']['uid_nid'] = [
        'uid',
        'nid',
      ];
    return $aSchema;
  }
}
Gogowitsch’s picture

Component: base system » entity system
Status: Active » Closed (works as designed)

I'd say I close this very old feature request as I believe the feature is in core already.