Problem/Motivation

SqlContentEntityStorage::mapToStorageRecord sends update statements that includes IDENTITY fields that need to be updated, such as: UPDATE xxx SET nid = 1, property0 = :value0 WHERE nid = 1;. This is not supported in SQL Server because although there is no actual update happening it is explicitly telling the database engine that you wish to perform an update.

Question: Is it correct to allow UPDATE statements that change (even if new value is same as previous) IDENTITY values?

IDENTITY column values are immutable.

Proposed resolution

Remaining tasks

User interface changes

API changes

Original report by david_garcia

CommentFileSizeAuthor
#158 2342699-158.patch1.03 KBtuutti
#148 2342699-2-148.patch5.51 KBalexpott
#144 2342699-144.test.patch1.97 KBplach
#140 2342699-140.patch3.54 KBalexpott
#140 133-140-interdiff.txt4.16 KBalexpott
#133 not-update-entity-serial-columns-2342699-133.patch5.3 KBbeakerboy
#131 not-update-entity-serial-columns-2342699-131.patch5.3 KBbeakerboy
#127 not-update-entity-serial-columns-2342699-127.patch5.53 KBbeakerboy
#123 not-update-entity-serial-columns-2342699-123.patch5.96 KBbeakerboy
#122 not-update-entity-serial-columns-2342699-122.patch5.65 KBbeakerboy
#115 not-update-entity-serial-columns-2342699-115.patch4.04 KBbeakerboy
#114 not-update-entity-serial-columns-2342699-113.patch3.64 KBbeakerboy
#113 not-update-entity-serial-columns-2342699-112.patch2.71 KBbeakerboy
#111 not-update-entity-serial-columns-2342699-111.patch2.05 KBbeakerboy
#106 drupal-paragraphs-revision-2342699-106.patch3.32 KBrakshith.thotada
#99 interdiff-2342699-90-98.txt3.28 KBmradcliffe
#98 not-update-entity-serial-columns-2342699-98.patch2.71 KBbeakerboy
#90 not-update-entity-serial-columns-2342699-90.patch2.58 KBbeakerboy
#89 not-update-entity-serial-columns-2342699-89.patch2.58 KBbeakerboy
#88 not-update-entity-serial-columns-2342699-88.patch2.41 KBbeakerboy
#87 not-update-entity-serial-columns-2342699-87.patch2.27 KBbeakerboy
#86 not-update-entity-serial-columns-2342699-86.patch1.59 KBbeakerboy
#85 not-update-entity-serial-columns-2342699-85.patch1.88 KBbeakerboy
#84 not-update-entity-serial-columns-2342699-84.patch942 bytesbeakerboy
#83 not-update-entity-serial-columns-2342699-83.patch941 bytesbeakerboy
#79 not-update-entity-serial-columns-2342699-78.patch829 bytesbeakerboy
#78 not-update-entity-serial-columns-2342699-75.patch740 bytesbeakerboy
#77 not-update-entity-serial-columns-2342699-75.patch740 bytesbeakerboy
#74 not-update-entity-serial-columns-2342699-74.patch729 bytesbeakerboy
#73 not-update-entity-serial-columns-2342699-71.patch728 bytesbeakerboy
#72 not-update-entity-serial-columns-2342699-71.patch742 bytesbeakerboy
#64 drupal-2342699-do-not-update-entity-serial-columns-64.patch7.17 KBruloweb
#58 interdiff-2342699-58.txt679 bytesmadhavvyas
#58 not-update-entity-serial-columns-2342699-58.patch679 bytesmadhavvyas
#53 not-update-entity-serial-columns-2342699-53.patch7.24 KBmadhavvyas
#50 sqlcontententitystorage-2342699-49.patch6.98 KBnitesh sethia
#49 sqlcontententitystorage-2342699-49.patch6.98 KBnitesh sethia
#46 drupal-2342699-do-not-update-entity-serial-columns-5_46.patch6.59 KBdeepakaryan1988
#37 drupal-2342699-do-not-update-entity-serial-columns-5.patch6.05 KBdavid_garcia
#35 drupal-2342699-do-not-update-entity-serial-columns-5.patch5.99 KBdavid_garcia
#33 drupal-2342699-do-not-update-entity-serial-columns-5.patch5.99 KBdavid_garcia
#27 drupal-2342699-do-not-update-entity-serial-columns-5.patch6.13 KBdavid_garcia
#20 drupal-2342699-do-not-update-entity-serial-columns-5.patch3.99 KBdavid_garcia
#15 drupal-2342699-do-not-update-entity-serial-columns-5.patch4.29 KBdavid_garcia
#12 drupal-2342699-do-not-update-entity-serial-columns-5.patch2.59 KBdavid_garcia
#11 drupal-2342699-do-not-update-entity-serial-columns-5.patch848 bytesdavid_garcia
#6 drupal-2342699-do-not-update-entity-serial-columns-5.patch847 bytesmradcliffe

Comments

david_garcia’s picture

Project: Drupal driver for SQL Server and SQL Azure » Drupal core
Version: 8.x-1.x-dev » 8.0.x-dev
Component: Code » database system

I think this belongs to core:

Is it correct to allow UPDATE statements that change (even if new value is same as previous) PRIMARY KEY values?
Does it make sense?

I guess the database driver could be modified to remove primary key fields from updates, but does not look like a good solution to me.

Actually it is not primary keys that are not updatable in SQL Server, but IDENTITY fields. IDENTITY columns are created for SERIAL fields in Drupal.

IDENTITY column values are immutable.

mradcliffe’s picture

Title: ContentEntityDatabaseStorage tries to update primary key values by default » ContentEntityDatabaseStorage tries to update identity/serial values by default
Issue summary: View changes

Cool. Added issue summary template and tried to clarify the issue based on your recent comment. Thanks.

plach’s picture

Component: database system » entity system

Moving to the proper queue.

david_garcia’s picture

I've boosted this to Major. Without this issue solved we will never see D8 running on SQL Server.

I know it's just 10,000 sites (0.1%), but the issue itself makes sense.

david_garcia’s picture

Priority: Normal » Major
mradcliffe’s picture

Title: ContentEntityDatabaseStorage tries to update identity/serial values by default » SqlContentEntityStorage tries to update identity/serial values by default
Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new847 bytes

I'm pretty sure there is a test that specifically tests updating a serial field so this is going to fail.

This only fixes it for entities.

david_garcia’s picture

Status: Needs review » Reviewed & tested by the community

Looks good and fixes original issue.

mradcliffe’s picture

I guess there was not a test that updates an entity's identity/serial column. I think this may need a test in system module as well.

berdir’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

I'm not sure if we can write a useful test for this but we can try.

The change is wrong however, there is a method that should be used for this in 8.x: isNew()

david_garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new848 bytes

Tested, it's working OK now, D8 starts to be usable on SQL Server with this!

Fixed the ->isNew() issue.

david_garcia’s picture

1) Improved original implementation code readability.

2) With the change, revision management was all broken. The disturbing thing about that is that Drupal Tests were not able to detect a completely broken entity revision management sql storage.

3) Fixed revision management in new patch.

Remaining tasks: investigate why tests were not deteting the issue, and propose tests if needed.

Status: Needs review » Needs work

The last submitted patch, 12: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

david_garcia’s picture

what a mess...

david_garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new4.29 KB

Let's see how this new one behaves with tests.

Status: Needs review » Needs work

The last submitted patch, 15: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

berdir’s picture

  1. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -927,7 +927,7 @@ protected function doSave($id, EntityInterface $entity) {
    -          ->condition($this->idKey, $record->{$this->idKey})
    +          ->condition($this->idKey, $entity->{$this->idKey}->value)
    

    If you switch to $entity, then use the id() method instead of accessing the field directly.

  2. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1086,13 +1085,23 @@ protected function mapToStorageRecord(ContentEntityInterface $entity, $table_nam
    +        $serial_and_void = empty($value) && $serial;
    +        // Do not set serial values if this is a new entity
    +        // serials are inmutable and autoincremental.
    +        // @see https://www.drupal.org/node/2342699
    +        $serial_and_not_new = (!$entity->isNew()) && $serial;
    +        // Prevent setting serial field values.
    +        if ($serial_and_void || $serial_and_not_new) {
    +          continue;
             }
    

    This seems a lot more complicated than it has to be? both checks include serial, so something like this would IMHO be much more readable:

    // Skip serial fields for existing entities or if the value is empty.
    if ($serial && (!$entity->isNew() || empty($value)) {
      continue;
    }
    
  3. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1171,13 +1180,13 @@ protected function saveRevision(EntityInterface $entity) {
    +      if (!isset($entity->{$this->revisionKey}->value)) {
    ...
    +          ->fields(array($this->revisionKey => $entity->{$this->revisionKey}->value))
    
    @@ -1185,14 +1194,11 @@ protected function saveRevision(EntityInterface $entity) {
    +        ->condition($this->revisionKey, $entity->{$this->revisionKey}->value)
    ...
    +    return $entity->{$this->revisionKey}->value;
    

    Same here, use getRevisionId(). Note that this won't work with isset(), so you will need to do a !== NULL or so instead.

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 15: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

david_garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new3.99 KB

@bedir

1. Done, makes sense.

2. I also don't like it like that, but I wanted to keep as much comments as possible and looked into Drupal coding standards where they recommend doing that rather than breaking the condition into several lines to keep the comments. Anyways, I am trying something new here in the last patch.

3. Done, makes sense.

My local tests are broken, so I will need to mess up a little with the .org tests.

david_garcia’s picture

BTW: Is this supposed to be the way to check if a column is serial? isColumnSerial is just checking if this is ID or Revision Id, but what about other serial fields. Shouldn't this check depend on the schema type?

protected function isColumnSerial($table_name, $schema_name) {
    $result = FALSE;

    switch ($table_name) {
      case $this->baseTable:
        $result = $schema_name == $this->idKey;
        break;

      case $this->revisionTable:
        $result = $schema_name == $this->revisionKey;
        break;
    }

    return $result;
  }

Status: Needs review » Needs work

The last submitted patch, 20: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

mradcliffe’s picture

Yeah, that's not a really good method name if all it does is that.

david_garcia’s picture

So, last patch has many failures, but looking into it that is (at least some of the failurse) because isColumnSerial is failing to properly tell if a column is serial or not. Making the asumption that if a field is the ID or the REVISION ID of the entity it must be serial is not reliable.

I need some help here, I'm totally lost with the new way of defining database Schema's in D8.

I am trying to retrieve storage schema specifications by means of:

$this->getStorageSchema();

in the scope of a SqlContentEntity class. But there is no hint of "serial" field information inside the provided schema.

NID field appears be "int" everywhere but according to Schema API it is "serial". But the field in database is created as "serial" (int with autoincremental) so I guess at some point Drupal is able to tell that the NID field from the NODE entity is serial, I just don't seem to be able to retrieve that information.

This 5 minute patch is transforming into a nightmare, looks like a chain of some broken stuff that was holding together thanks to the loose behaviour of mySQL.

mradcliffe’s picture

I ran into similar confusion when I investigated mapToStorageRecord previously...

Back in Drupal 7, we had the concept of a field which had its "schema" defined in hook_field_storage or whatever where a field api field could define multiple columns, etc... for its field tables. In Drupal 8, every property on an entity is considered a "field" for consistency. Many fields are 1:1 (nid, vid, uid, etc...) where as complex field types and field api fields have that field/column storage definition.

So in mapToStorageRecord() the code first goes through an entity's fields, and for each field, it goes through its column storage definition. In that first loop, it calls getFieldStorageDefinitions(). I think this has the Schema API type of "serial" defined IIRC whereas when it loops through column storage it has the standard SQL types.

I hope that helps.

david_garcia’s picture

I deeply inspected getFieldStorageDefinitions(), getTableMapping() and getStorageSchema() none of them is able to tell the NID field of the NODE table is "serial", it is shown everywhere to be "integer".

I am even unable to tell what drupal data type is the NID column in NODE by using drupal_get_complete_schema(), this is just returning a handfull of tables, but not the NODE table schema.

What is the way in D8 to tell the storage data type of an entity's property?

I am starting to think that whoever wrote the isColumnSerial the first time was unable to acquire that information so decided to implement as is now.

david_garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new6.13 KB

Bad patch, but let's see how it does against tests.

Status: Needs review » Needs work

The last submitted patch, 27: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

plach’s picture

+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -1113,20 +1116,9 @@ protected function mapToStorageRecord(ContentEntityInterface $entity, $table_nam
+  protected function isColumnSerial($table_name, $column) {
+    $storageschema = $this->getStorageSchema()->EntitySchema($this->entityType);
+    return $storageschema[$table_name]['fields'][$column]['type']=== 'serial';

This is not an option, sorry. We tried hard to remove the need to use schema at runtime, we should not add it back here. The basic idea behind the entity storage is that we know how the schema is shaped because it's derived from entity and field definitions. We don't need to go asking the storage schema handler whether a field is serial, we know which ones are. What's wrong with the current code?

plach’s picture

  1. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1085,14 +1083,19 @@ protected function mapToStorageRecord(ContentEntityInterface $entity, $table_nam
    +        // Serial fields should only be set on entity creation,
    +        // even if a value is provided. Serials are autoincremental ¶
    +        // and inmutable
    +        // so database takes care of everything.
    

    This comment is not wrapping at column 80. Also should be "immutable" :)

  2. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1085,14 +1083,19 @@ protected function mapToStorageRecord(ContentEntityInterface $entity, $table_nam
    +        // @see https://www.drupal.org/node/2342699
    

    We usually link only follow-ups in code, not sure why we have another reference a few lines above but no need to add one. Git blame can be used to find the issue if needed.

  3. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
    @@ -428,6 +428,10 @@ protected function checkEntityType(EntityTypeInterface $entity_type) {
    +  public function EntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
    +    return $this->getEntitySchema( $entity_type, $reset);
    +  }
    +  ¶
       /**
    

    The ::getEntitySchema() method is protected for a good reason, which is we don't need to expose the schema array. This should be removed altogether.

david_garcia’s picture

@plach: Glad to see someone with knowledge of how EntityStorage works jumping in, I am very lost here. Sorry for the coding standards, I was just trying this to overally pass tests as a starting point.

What concerns me now most about this issue is how SqlContentEntityStorage::isColumnSerial works.

We don't need to go asking the storage schema handler whether a field is serial, we know which one are.

Well, this is the ContentEntityStorage (in charge of dumping the entity to database) trying to figure out what the type of a field is in the database.

That means that, as per isColumnSerial current implementation, any Entity's PrimaryKey or EntityRevision Revision Key is assumed to be SERIAL (and cannot be differently) and all other columns ARE NOT SERIAL (and this also cannot be differently).

And if your entity does not work like this, then the ContentEntityStorage that is in charge of dumping the Entity into the database has now way of telling what database type a column is. So basically, all Entities in Drupal should work like that.

Investigating this issue I saw that in D8 schema is inferred from Entity's field definition, in Entity/Node.php:

$fields['nid'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Node ID'))
      ->setDescription(t('The node ID.'))
      ->setReadOnly(TRUE)
      ->setSetting('unsigned', TRUE);

Then StorageSchemaHandler is forcing to be serial any key that is of type integer when constructing the Schema:

protected function processIdentifierSchema(&$schema, $key) {
    if ($schema['fields'][$key]['type'] == 'int') {
      $schema['fields'][$key]['type'] = 'serial';
    }
    unset($schema['fields'][$key]['default']);
  }

Then why not use this insted (can't even wonder if it works):

   $fields['nid'] = BaseFieldDefinition::create('serial')
      ->setLabel(t('Node ID'))
      ->setDescription(t('The node ID.'))
      ->setReadOnly(TRUE)
      ->setSetting('unsigned', TRUE);

I can workaround this issue in the SQL Server database driver (and I guess it will need to be like that because looks like D6 migration is asuming you can UPDATE and/or INSERT values into a serial column, wich you can actualy do in SQL Server but with special techniques), but I don't think it is formally correct to have this sort of statement being issued against the database:

UPDATE xxx SET nid = 1, property0 = :value0 WHERE nid = 1

Futhermore, why does SqlContentEntityStorage have a getStorageSchema() and getFieldStorageDefinitions() method that is saying that storage type for the NID is 'int' instead of 'serial'?

mradcliffe’s picture

@plach wrote:

This is not an option, sorry. We tried hard to remove the need to use schema at runtime, we should not add it back here. The basic idea behind the entity storage is that we know how the schema is shaped because it's derived from entity and field definitions. We don't need to go asking the storage schema handler whether a field is serial, we know which ones are. What's wrong with the current code?

drupal_write_record() was verbose and a monster, but at least it took care not to make assumptions about writing to the database. The implementation of mapToStorageRecord is very naive and makes assumptions that cannot be made for writing to a SQL database. It is absolutely necessary that code that sets up writes to a database knows how to write to a database i.e. knows what it should or should not do. The class name is SqlContentEntityStorage and thus it should behave how SQL expects it to.

@david_garcia wrote:

That means that, as per isColumnSerial current implementation, any Entity's PrimaryKey or EntityRevision Revision Key is assumed to be SERIAL (and cannot be differently) and all other columns ARE NOT SERIAL (and this also cannot be differently).

I agree with @david_garcia that it should be possible to add other sequence fields, either base field definitions or complex field definitions, for an arbitrary content entity.

@david_garcia wrote:

And if your entity does not work like this, then the ContentEntityStorage that is in charge of dumping the Entity into the database has now way of telling what database type a column is. So basically, all Entities in Drupal should work like that.

However, I think that content entities need to be consistent. It is safe to assume that a content entity's primary key and revision key should behave consistently with all other content entity implementations and be identity columns. The current patch needs work - whatever mapToStorageRecord calls needs to distinguish which serial field is an identity type for a particular table. On the revision table, it's the revision field, on the entity table it's the id field.

Perhaps isColumnSerial() is important, but isFieldSerial() is also important for the logic of whether to treat Id or Revision fields as serial for whichever operation.

@david_garcia wrote:

...(and I guess it will need to be like that because looks like D6 migration is asuming you can UPDATE and/or INSERT values into a serial column, wich you can actualy do in SQL Server but with special techniques)...

Migrate worries me too for pgsql driver.

david_garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new5.99 KB

Makes sense to have a consistent entity design all accross drupal regarding keys and serial columns, documentation should be extremely clear about this:

- Serial fields do not exist, you can only have a serial column per entity and that is it's key and it must always be set to 'integer'.
- If a key in an entity is an 'integer', then it is automatically assumed to be serial. Other types are allowed though... That means that you cannot have an entity key to be integer and not auto incremental, but you can have an entity key being a string?

I am still not fond of isColumnSerial implementation, if these asumptions are all made inside StorageSchemaHandler then why not ask that class what has it decided to do with keys and serials. Complete agree with this:

@mradcliffe wrote:

The implementation of mapToStorageRecord is very naive and makes assumptions that cannot be made for writing to a SQL database. It is absolutely necessary that code that sets up writes to a database knows how to write to a database i.e. knows what it should or should not do. The class name is SqlContentEntityStorage and thus it should behave how SQL expects it to.

Status: Needs review » Needs work

The last submitted patch, 33: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

david_garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new5.99 KB

Found the annoying bug in the patch, let's retest.

Status: Needs review » Needs work

The last submitted patch, 35: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

david_garcia’s picture

Status: Needs review » Needs work

The last submitted patch, 37: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

david_garcia’s picture

Status: Needs work » Needs review

Failing tests are amazingly passing in my local environment with latest patch (SQL Server though...), try to retest.

Status: Needs review » Needs work

The last submitted patch, 37: drupal-2342699-do-not-update-entity-serial-columns-5.patch, failed testing.

plach’s picture

@david_garcia:

[...] if your entity does not work like this, then the ContentEntityStorage that is in charge of dumping the Entity into the database has now way of telling what database type a column is. So basically, all Entities in Drupal should work like that.

Yep, this is how the default SQL entity storage is supposed to work. If you have an entity type that needs to behave differently you just need to provide an alternative storage class.

Then why not use this insted (can't even wonder if it works):

Because 'serial' is a Schema API type, while field definitions are using Type Data API types, for which serial is meaningless: it just cares about the native type.

I don't think it is formally correct to have this sort of statement being issued against the database.

I'm not saying it's correct, I totally agree with the goal of avoiding this kind of update statements. I'm just saying we can rely on a known schema to deal with them.

why does SqlContentEntityStorage have a getStorageSchema() and getFieldStorageDefinitions() method that is saying that storage type for the NID is 'int' instead of 'serial'?

The storage schema needs to be instantiated only in rare conditions, that is when dealing with schema updates, that are forwarded from the storage class to the storage schema class because the latter is not part of the "public API", in fact not every entity storage would require schema handling (the Mongo Storage will not, probably).

@mradcliffe:

The implementation of mapToStorageRecord is very naive and makes assumptions that cannot be made for writing to a SQL database.

I can only repeat that we are making no assumptions, we know how the schema is shaped. If the current implementation of mapToStorageRecord is incorrect or does not take into account all possible SQL flavors I'm all for fixing it, I'm just saying we don't need to retrieve the schema, because it's generated, hence it's well known.

I agree with @david_garcia that it should be possible to add other sequence fields, either base field definitions or complex field definitions, for an arbitrary content entity.

AFAIK only one serial field is allowed for each table on most RDBMS, anyway, as I said above, if you need a different behavior you can just code your own classes. The current approach has worked well for all core entity types and lots of contrib ones so far.

@david_garcia:

That means that you cannot have an entity key to be integer and not auto incremental, but you can have an entity key being a string?

Nope :) That just means that most entity types behave that way. For instance, the User storage class overrides isColumnSerial() to use a non-serial integer id column.

I am still not fond of isColumnSerial implementation, if these asumptions are all made inside StorageSchemaHandler then why not ask that class what has it decided to do with keys and serials.

From an architectural POV you are totally right: it would be better if this kind of logic were encapsulated in the storage schema class. Here we decided to go this way to avoid the need of instantiating the storage schema class on every request. This is a bit like cheating but given how much coupled the storage and storage schema classes are, it should not be a problem in practice. This is not set in stone however, we are still evaluating these implementation details: a possible alternative could be moving this knowledge into the table mapping class and make the storage and storage schema rely on it. However this is a different issue :)

david_garcia’s picture

Ok... this issue was great learning on to how EntityStorage works in D8 :)

A briefing of things to do:

- First we need to fix issuing update statements that have identity updates, while preserving al other behaviour. That's what my last patch tries to achieve, but fails some tests. I cannot replicate locally, they are all passing. I even moved from SQL Server to MySQL to run the tests, and still passing locally.

- Figure out why although patch in #6 passed tests, entity updates were left completely broken. Will probably require some new tests to be writen.

- Open a new Issue to move forward on this discussion:

From an architectural POV you are totally right: it would be better if this kind of logic were encapsulated in the storage schema class. Here we decided to go this way to avoid the need of instantiating the storage schema class on every request. This is a bit like cheating but given how much coupled the storage and storage schema classes are, it should not be a problem in practice. This is not set in stone however, we are still evaluating these implementation details: a possible alternative could be moving this knowledge into the table mapping class and make the storage and storage schema rely on it. However this is a different issue :)

plach’s picture

Issue tags: +entity storage
jhedstrom’s picture

Issue tags: +Needs reroll

Patch is no longer applying. This is tagged as needing tests, but it seems like a difficult thing to test for.

deepakaryan1988’s picture

Status: Needs work » Needs review
StatusFileSize
new6.59 KB

Re-rolled!

Status: Needs review » Needs work
nitesh sethia’s picture

Assigned: Unassigned » nitesh sethia
nitesh sethia’s picture

Assigned: nitesh sethia » Unassigned
StatusFileSize
new6.98 KB

Rerolled the patch.

nitesh sethia’s picture

Status: Needs work » Needs review
StatusFileSize
new6.98 KB

Changing the status to In review.

Status: Needs review » Needs work

The last submitted patch, 50: sqlcontententitystorage-2342699-49.patch, failed testing.

david_garcia’s picture

It would probably be a good idea to find out where are the 6 test failures comming from in #37 before introducing the extra code in #50.

madhavvyas’s picture

Patch re-rolled for #39

madhavvyas’s picture

Status: Needs work » Needs review

The last submitted patch, 49: sqlcontententitystorage-2342699-49.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 53: not-update-entity-serial-columns-2342699-53.patch, failed testing.

sharique’s picture

+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -783,7 +783,60 @@ protected function doSaveFieldItems(ContentEntityInterface $entity, array $names
+              ->fields((array) $record)

What this $record is? It is giving syntax error.

madhavvyas’s picture

Removed $record variable as suggested. It was not used in query.

madhavvyas’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll

Status: Needs review » Needs work

The last submitted patch, 58: not-update-entity-serial-columns-2342699-58.patch, failed testing.

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.

audriusb’s picture

it is still a problem in v8.1.2

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.

ruloweb’s picture

Fix a few brackets in patch #53 (which is based on #37). Added also feedback in #57.

This currently works for Drupal 8.2.3.

I haven't addressed the failing tests.

ruloweb’s picture

Status: Needs work » Needs review

Let's test it, my local MSSQL is quiet slow.

Status: Needs review » Needs work

The last submitted patch, 64: drupal-2342699-do-not-update-entity-serial-columns-64.patch, failed testing.

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.

beakerboy’s picture

Is there a stutus update on this issue? Anything I can do to test it?

beakerboy’s picture

Is there a simple change I can make to allow users to update values of custom entities? I could either modify core to prevent " SET id={id}" from appearing in entity update SQL, or add something to my custom module to rewrite the SQL statement before it executes. I attempted to use some of the simpler patches on my Drupal 8.4 site, but it caused my site to stop responding.

beakerboy’s picture

As an update. I fixed this with the following small change to SqlContentEntityStorage.php

if ($shared_table_fields) {
      $record = $this->mapToStorageRecord($entity->getUntranslated(), $this->baseTable);
      // Create the storage record to be saved.
      if ($update) {
        // 2 new lines here - Cast $record to an array and remove the id element
        $record_a = (array) $record;
        unset($record_a["id"]);

        $default_revision = $entity->isDefaultRevision();
        if ($default_revision) {
          $this->database
            ->update($this->baseTable)
 // replaced this            ->fields((array) $record)
            ->fields($record_a)
            ->condition($this->idKey, $record->{$this->idKey})
            ->execute();
        }
beakerboy’s picture

Patch File for my change.

beakerboy’s picture

Second Try. Removing DOS line endings.

beakerboy’s picture

Adding Missing Newline

beakerboy’s picture

beakerboy’s picture

beakerboy’s picture

StatusFileSize
new740 bytes

Last try before I give up.

beakerboy’s picture

beakerboy’s picture

StatusFileSize
new829 bytes
beakerboy’s picture

Status: Needs work » Needs review

Please review and let me know if there is anything I need to do to get this into core.

david_garcia’s picture

Status: Needs review » Needs work

@Beakerboy Sorry but the last patch is a dirty hack that does not fit the architecture. Please see the work in all the previous posts. At some point this got close to being solved, but needed test coverage. Thanks!

beakerboy’s picture

@david_garcia I would say it’s a very clean hack...three lines and breaks absolutely nothing. Everything else has been in the works for years, and continues to fail unit tests. Let me know where you feel the changes should be made and I’ll look into it. I like simple solutions over over-engineered projects. This code efficiently removes the problem, exclusively where it is an issue.

I’ve never used SimpleTest to do unit tests. How would you propose testing this? The way I would approach it would be to find where an entity update is tested, and examine the $query object to ensure that “id” is not in the field array, or to pass $query->__toString() through a regular expression to ensure it does not match “SET.*id=.*WHERE”.

beakerboy’s picture

Here is a version that checks the id status of each field, and only removes it if it is the base table's idKey

beakerboy’s picture

StatusFileSize
new942 bytes

Missing Line break

beakerboy’s picture

StatusFileSize
new1.88 KB

This version handles the revision table as well.

beakerboy’s picture

StatusFileSize
new1.59 KB

The previous version was using an incorrect $record_array. If this works, then the alias storage will need to be updated.

beakerboy’s picture

This fixes the issue with the AliasStorage object

beakerboy’s picture

StatusFileSize
new2.41 KB

The pid element in the $fields array is used elsewhere. Putting it back in, but after the update query is constructed.

beakerboy’s picture

Here is an 8.5 patch

beakerboy’s picture

StatusFileSize
new2.58 KB

Typo in the previous patch. Please offer suggestion on the best way to test this. I'm more than happy to write a test or two. If you feel there is a better way to accomplish this that does not require refactoring several objects, please offer constructive advice. I would love it if someone with a sql server test install could test this patch. The only thing I think I might want to change is to rename $record_array to $fields, for consistency with other calls to the update method.

beakerboy’s picture

Status: Needs work » Needs review
beakerboy’s picture

Is there anyone who could test this patch on a sql server installation? Can anyone recommend a way to unit test this? I have asked on both StackExchange and the drupal slack channel with no responses.

I found a unit test in /core/tests/Drupal/KernelTests/Core/Database/UpdateTest.php which specifically tests that primary keys CAN be updated. This test will need to be removed before SQL Server will pass testing.

beakerboy’s picture

Issue tags: -Needs tests

Nobody on the Slack channel, stackExchange, the IRC channel, or the support forums here have been able to offer any advice on how to test this fix.

rakshith.thotada’s picture

Hello @beakerboy Thanks for the patch.
We have our production running on Windows server and when we used SqlSrv module - we faced this issue.

I will mark this as RTBC. Thanks for this Contribution.

rakshith.thotada’s picture

Assigned: Unassigned » rakshith.thotada
Status: Needs review » Reviewed & tested by the community
berdir’s picture

Assigned: rakshith.thotada » Unassigned

I think that all existing tests continue to work is enough test coverage, agreed that this would be very hard to test without very low-level unit test that would test the actual arguments to the query builder methods.

I also added test runs for PostgreSQL/SQlite.

catch’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -842,9 +842,15 @@ protected function doSaveFieldItems(ContentEntityInterface $entity, array $names
+          // We must remove the serial field to prevent it from being included in the

This goes over 80 characters. We should also explicitly mention that updating the serial fails on SQL server here I think.

beakerboy’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new2.71 KB

The comment has been changed.

mradcliffe’s picture

StatusFileSize
new3.28 KB

I made an interdiff of patch 89 and 90 manually via interdiff not-update-entity-serial-columns-2342699-90.patch not-update-entity-serial-columns-2342699-98.patch, and attached it.

I didn't have time to review the additional changes in #90.

beakerboy’s picture

beakerboy’s picture

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 98: not-update-entity-serial-columns-2342699-98.patch, failed testing. View results

beakerboy’s picture

Status: Needs work » Reviewed & tested by the community

The only change since #90 is in comments. #90 passed tests, but the test server is out of hard drive space, which is preventing #98 from running.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 98: not-update-entity-serial-columns-2342699-98.patch, failed testing. View results

beakerboy’s picture

Status: Needs work » Reviewed & tested by the community

Test server is back online. PHP 5.6 & MySQL 5.5 passed, others are queued.

rakshith.thotada’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new3.32 KB

Hello @Beakerboy,

I used your Patch - https://www.drupal.org/files/issues/not-update-entity-serial-columns-234....
Everything Worked fine. But when we use Paragraphs, We faced an issue with creation/updation of node.

The error was - Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Cannot update identity column 'revision_id'.: UPDATE paragraphs_item_revision.

So I had to create the new patch and it will fix the issue here. Please review once.

https://www.drupal.org/files/issues/drupal-paragraphs-revision-2342699-1...

plach’s picture

I'll have a look ASAP.

plach’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -843,9 +843,16 @@ protected function doSaveFieldItems(ContentEntityInterface $entity, array $names
+            unset($record_array[$this->idKey]);

@@ -855,10 +862,17 @@ protected function doSaveFieldItems(ContentEntityInterface $entity, array $names
+              unset($record_array[$this->revisionKey]);

@@ -1088,9 +1102,16 @@ protected function saveRevision(ContentEntityInterface $entity) {
+        unset($record_array[$this->revisionKey]);

The general direction of this patch is ok IMO, but I think this could be fixed in a single place by adjusting the logic in ::mapToStorageRecord(). We are already dealing with SQL server towards the bottom of the loop, so that seems to be the right place to address this issue. We'd just need to avoid setting the value in $record in the first place, regardless of $value being set, when we are going to perform an update query and we have a serial (identity) column. We can easily check this via ::isNew() or ::isNewRevision() depending on the table being the base table or the revision table.

rakshith.thotada’s picture

@plach

Thanks for reviewing it. We would still need those keys in $record array, as we use those Identity column/Primary key as condition in Update queries.

Let me know your thoughts on this.

plach’s picture

We have $entity: we can populate conditions via $entity->id() and $entity->getRevisionId().

beakerboy’s picture

I've changed the logic in mapToStorageRecord as suggested. Let me know if this looks better. It seems to work on my local install.

plach’s picture

Status: Needs work » Needs review
beakerboy’s picture

StatusFileSize
new2.71 KB

last patch was missing the changes outside mapToStoarageRecord()

beakerboy’s picture

StatusFileSize
new3.64 KB

wrong drupal repo on previous. This one is correct.

beakerboy’s picture

StatusFileSize
new4.04 KB

Last patch was missing calls to getValue(). This patch seems to fix updates on custom entities, but node updates fail.

This patch probably needs an edit for readability: /r/->getValue()[0]['values']/->value/g

Status: Needs review » Needs work
plach’s picture

Didn't look at the patch, but $entity->get($name)->value should be enough to retrieve the field value.

beakerboy’s picture

Which is preferable, $entity->{$this->idKey}->value or $entity->get($this->idKey)->value?

plach’s picture

They are the same, I personally prefer to use ::get() when the field name is stored in a variable, but that's just me :)

berdir’s picture

> They are the same, I personally prefer to use ::get() when the field name is stored in a variable, but that's just me :)

That's me too, +1.

Mixologic’s picture

Can somebody help me figure out why all the patches in #111,#113-#115 are generating so much output as to completely fill the testbot disks? We didn't used to have this problem, and this is the third time this month that some bad patches create *mountains* of output, I suspect its not just an accident here, but somehow we've ratcheted up some logging or error handling that is compounding the issue.

Its causing the disks to fill up to the point that the testbot dispatcher cannot tell if the disks are full, and pull the testbot out of rotation. Which causes it to keep running whatever is in the queue, thus, killing testing for everything thats waiting for a test.

Please be careful when resubmitting any of the patches in #111-115 - Please run it locally first, at least to prove that the error common in all of those result sets is not going to replicate twenty thousand times.

And if anybody has any ideas about what may have recently changed in core to create all this extra output, I would certainly appreciate a pointer.

Thanks.

beakerboy’s picture

Here is a 8.4 patch that works on my system for custom entities, nodes, and node revisions. However, it includes a slight API change. The format is now starting to look like what was being done at around patch #12...which is where nobody was ever able to resolve all the testing failures, and prompting me to take a different approach. Maybe it has to do with entity->get($this->idKey)->value not matching up with $record->{$this->idkey}, such that replacing the later with the former causes failures?

beakerboy’s picture

StatusFileSize
new5.96 KB

I moved the call to fetch the $record inside each of the "update" and "insert" blocks since the necessary parameters will be different.

beakerboy’s picture

Status: Needs work » Needs review

Please review. I can simplify this patch by using the existing $update variable within doSaveFieldItems() and calling mapToStorageRecord() once like it was originally. Please review and I'll roll the simplification out tomorrow. I don't see a way to accomplish this without changing the API like I did. mapToStorageRecord() would have to redo all the tests that the calling functions do to determine if the $query will be an update or insert.

tacituseu’s picture

@Mixologic: posted a reply in old testing issue so as not to clutter this one.

plach’s picture

Looking good, thanks!

I still have to review the code more in depth, but this looks promising. A simplification would be welcome of course :)

+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -959,11 +960,15 @@ protected function saveToSharedTables(ContentEntityInterface $entity, $table_nam
+   * @param bool $update
+   *   (optional) If set to true, serial fields will not be included, even if
+   *   their value has been set. This is important for update queries on some
+   *   databases. ¶

Trailing whitespace. Also, let's use TRUE please.

beakerboy’s picture

StatusFileSize
new5.53 KB

Here is a slightly simplified version. The API change is still in it, but instead of hard-coding a few TRUE s in the function call, I set and passed in an $update variable.

berdir’s picture

  1. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -959,11 +959,15 @@ protected function saveToSharedTables(ContentEntityInterface $entity, $table_nam
        *   (optional) The table name to map records to. Defaults to the base table.
    +   * @param bool $update
    +   *   (optional) If set to TRUE, serial fields will not be included, even if
    +   *   their value has been set. This is important for update queries on some
    +   *   databases.
    

    usually update refers to updating an existing entity. But for the revision case, saving as a new revision is also an update in how we use it in general in the entity system.

    If we need this argument then I would recommend a more explicit $include_serial_fields (or something like that) argument.

    The alternative would be a new wrapper method like mapToStorageRecordWithoutSerialFields() but adding a new optional argument to a protected method should be fine IMHO.

  2. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1086,19 +1089,17 @@ protected function saveRevision(ContentEntityInterface $entity) {
             ->fields((array) $record)
    -        ->condition($this->revisionKey, $record->{$this->revisionKey})
    +        ->condition($this->revisionKey, $entity->get($this->revisionKey)->value)
    

    if you're working with the entity then you can just use $entity->getRevisionId() ?

beakerboy’s picture

@Berdir

1. The $update parameter was already defined in this class as whether or not the SQL statement would be an update statement or not. I just maintained this. I would rather change the name than make a wrapper for simplicity.

2. I can change that, no problem.

berdir’s picture

1. Yes, it existed in one of two methods :) But that's kind of my point, in the doSaveFieldItems(), $update is correct, it's either a new new entity or not. But in the revision context, the meaning of $update isn't clear, so lets use a more specific variable name for the helper function that explicit about what it does.

beakerboy’s picture

Including suggestions from @Berdir

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.

beakerboy’s picture

StatusFileSize
new5.3 KB

With the end of Drupal 8.4 development...please test this 8.5 patch so we can keep this moving. Thanks!

rbrenton’s picture

This is still broken in the main branches. The patch #133 referenced works for us on SQL Server 2016.

rbrenton’s picture

Status: Needs review » Reviewed & tested by the community

This needs merged into at least 8.4.x-dev, 8.5.x-dev and 8.6.x-dev. I haven't checked earlier than 8.4.

alexpott’s picture

I'm not sure we're fixing this at the right level.

I'm wondering why

I guess the database driver could be modified to remove primary key fields from updates, but does not look like a good solution to me.

Was not attempted. The thing is contrib (or custom) will do things like what you see in AliasStorage. For me that makes this a db driver problem and not something that should be fixed in the entity storage level.

alexpott’s picture

If we do decide to go for #133 then I think we should add a test for the new logic in mapToStorageRecord() so can be sure not to break this in the future.

rbrenton’s picture

Responding to #136.

IMHO, #133 fixes it in the most correct place. If fixed at the driver level and later there is a need to update a primary key, the driver would be incorrect and we would have to return to #133 and patch it this way anyway. I think it would be ideal if the core did not send unnecessary fields to update to the driver. Also, there's still the fix in the patch for what looks like a line ordering error of $fields['pid'] = $pid in core/lib/Drupal/Core/Path/AliasStorage.php?

alexpott’s picture

@rbrenton the problem is wider than the entity system though. It's anything that updates a record in the database. Most contrib and custom modules are used with MySQL / Postgres and DrupalCI also offers SQLite coverage but we have no automated testing for a DB that behaves this way so if this isn't fixed in the DB layer there's a good chance something will be broken somewhere.

What I'm trying to say is that the restriction on not updating an identity column comes solely from mssql and the entity sql storage implementation will not be the only place this causes problems.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new4.16 KB
new3.54 KB

I've discussed this a bit with @amateescu in slack. He's pointed out that fixing this in the db driver level is going to be very expensive - mssql driver will have to get the schema for every table during an update and work stuff out.

I have two concerns:

  1. This has no test coverage
  2. The return of mapToStorageRecord() is mutable depending on whether you are inserting or updating - that just feels wrong to me.

So here's an even less testable version of #133 but the difference is that it doesn't change mapToStorageRecord(). The changes in that code concern me because it make the result mutable depending on whether you are updating or inserting whereas I think conceptually an entity with identical values should map to the same storage record regardless of whether you are inserting or updating. Therefore I think we should fix it closer to the queries by doing something like the patch attached.

Still no sure how to test this. Posting to see what people think and maybe someone can test on mssql.

alexpott’s picture

So @amateescu pointed out the that @plach asked for the changes to mapToStorageRecord in #108. As stated in #140 I'm not sure this is the right way to go because I don't think it makes sense to have a mutable storage record for different operations. It feels like the wrong axis to change that on.

beakerboy’s picture

@alexpott...any updates in your thoughts on this patch, or this issue in general?

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

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

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

plach’s picture

StatusFileSize
new1.97 KB

I discussed #141 with @alexpott: I'm not completely sold on that argument, but I'm fine with going that way. I'd rather see us making progress on this issue, given that the differences between the two approaches aren't likely to be that relevant in practice.

Regarding test coverage, we both agreed that the proper way to test these changes, would be to run our test suite on SQL server, so no need to add explicit coverage for that. OTOH while discussing possible alternatives to #140, I realized that we are missing an explicit test to cover entity ID assignment on creation, although we likely have implicit coverage for that via migration tests. I'm offering the attached patch as a complement to #140. Feel free to merge them, otherwise I'll open a separate issue for this.

If we don't end up merging the two patches, I'm +1 on RTBC-ing/committing #140.

beakerboy’s picture

@platch

Thanks for the update. I will test #140 on mssql shortly. Thinking ahead, do we need to be on the lookout for cases where a user creates an entity with additional IDENTITY fields beyond just the id column? Can a user create and entity with multiple IDENTITY fields? #140 appears to just remove "id", while #133 checks each field with isColumnSerial() and removes it if it is.

plach’s picture

I don't think entities were ever intended to have more than one ID field. I cannot completely rule out the possibility that a heavily customized entity type could try to implement two ID fields, but I'm very skeptical it would be possible to do that.

mradcliffe’s picture

DBTNG does allow to set serial type to multiple columns, but I don't think it's used in core.

I think it's theoretically possible for an entity to define multiple base field definitions that may have the serial type, but I don't think there's a test for it.

alexpott’s picture

StatusFileSize
new5.51 KB

@plach I think it is great to add an explicit test here. And whilst it does not 100% confirm the fix it does prove no regressions so adding it here makes sense. Wrt to multiple serial columns - does anyone have a use-case? We could open a follow-up to deprecate supporting that because it feels that doing multiple serial columns does not make a great deal of sense.

Patch attached merges #140 and #144.

plach’s picture

I don't think we need to worry about advanced use cases implying multiple serial columns: this is not how core entities work. An highly specialized entity type requiring multiple serial columns could extend the storage to deal with its use case.

I'm in favor of RTBC-ing #148 as soon as @Beakerboy (or someone else) confirms the patch is good for MSSQL.

mradcliffe’s picture

I agree with that. The patch makes sense and is documented.

beakerboy’s picture

Status: Needs review » Reviewed & tested by the community

The latest patch resolves the issue on my Drupal site. Thanks everyone for all the thought and work over the past 4 years to get this changed!

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.7.x and cherry-picked to 8.6.x, thanks!

  • catch committed c8f810e on 8.7.x
    Issue #2342699 by Beakerboy, david_garcia, alexpott, madhavvyas, Nitesh...

  • catch committed e4b3ec3 on 8.6.x
    Issue #2342699 by Beakerboy, david_garcia, alexpott, madhavvyas, Nitesh...

Status: Fixed » Closed (fixed)

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

jibran’s picture

tuutti’s picture

StatusFileSize
new1.03 KB

Some of our custom entities broke on core update (8.6.2 -> 8.6.7) and I tracked the issue to here:

-            ->condition($this->idKey, $record->{$this->idKey})
+            ->condition($this->idKey, $entity->get($this->idKey)->value)

This seems to assume that ID is stored in a property called value and breaks the update statements when using a field where that is not the case.

beakerboy’s picture

I’d suggest opening a new bug report. This one is already closed and the patch has been rolled out, so I don’t know if it would be re-opened. If you open a new report you can reference this issue, submit this patch, and run core tests against it. That would probably get more core developers attention since it’s a new report versus a comment on a closed one. Add as much detail as you can to your report, like how your custom entity is designed. It’s possible that there is some requirement that all entities have a ‘value’ property.

It took a year of prodding to get this issue fixed, so it’s possible yours may take some time as well.