[PR #10598] Support not Insertable/Updateable columns for entities with JOINED inheritance type #12479

Closed
opened 2026-01-22 16:14:10 +01:00 by admin · 0 comments
Owner

Original Pull Request: https://github.com/doctrine/orm/pull/10598

State: closed
Merged: Yes


Fix for https://github.com/doctrine/orm/issues/9467 when insert and update entity with joined inheritance + update values from database

  1. Entities with #[InheritanceType('JOINED')] attribute process by JoinedSubclassPersister, according to UnitOfWork::getEntityPersister():
    da9b9de590/lib/Doctrine/ORM/UnitOfWork.php (L3227-L3228)
  2. The persister override getInsertColumnList() without excluding notInsertable columns like parent do:
    da9b9de590/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php (L1478)
    so when it use prepared sql-statement with parameters prepared by parent (AbstractEntityInheritancePersister::prepareInsertData() reuse BasicEntityPersister::prepareInsertData() reuse BasicEntityPersister::prepareUpdateData() with $isInsert mode):
    da9b9de590/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php (L640-L659)
    we get error from database, e.g. postgresql:
    DOException: SQLSTATE[08P01]: <<Unknown error>>: 7 ERROR:  bind message supplies 4 parameters, but prepared statement "" requires 6
    
    So fixed JoinedSubclassPersister::getInsertColumnList(). There is no such error for update queries, because parent methods used in JoinedSubclassPersister::update(): BasicEntityPersister::prepareUpdateData() and BasicEntityPersister::updateTable().
  3. There were problems with logic to update entity properties with database values in generated columns (notInsertable|notUpdatable|version) after flush - JoinedSubclassPersister::assignDefaultVersionAndUpsertableValues():
    da9b9de590/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php (L548-L555)
    • flag which activates it (ClassMetadataInfo::$requiresFetchAfterChange) in both cases (executeInserts() and update()) doesnt inherited from entity parent-class. This fixed by tracking of parent mappings in ClassMetadataInfo::addInheritedFieldMapping() like it done for child entity in mapField() (may be add setter for factory):
      da9b9de590/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php (L2814-L2820)
    • it use parent select query to get generated columns, while it could be in both tables (child and parent), so override query builder in persister - JoinedSubclassPersister::fetchVersionAndNotUpsertableValues() - where added join (reuse JoinedSubclassPersister::getJoinSql()) and column aliases. Make parent extractIdentifierTypes() and $identifierFlattener make them protected.
    • because generated column may be in child tables logic should be after insert into child tables in persister insert() method to avoid LengthException('Unexpected empty result for database query.').
  4. For functional tests added JoinedInheritanceRoot entity, with children for each case and JoinedInheritanceChild to test root entity columns. Declare database default column values to avoid platform-specific columnDefinition. Use generated: 'ALWAYS' in hope to obtain error from update() method
**Original Pull Request:** https://github.com/doctrine/orm/pull/10598 **State:** closed **Merged:** Yes --- Fix for https://github.com/doctrine/orm/issues/9467 when insert and update entity with `joined` inheritance + update values from database 1. Entities with `#[InheritanceType('JOINED')]` attribute process by `JoinedSubclassPersister`, according to `UnitOfWork::getEntityPersister()`: https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/UnitOfWork.php#L3227-L3228 1. The persister override `getInsertColumnList()` without excluding `notInsertable` columns like parent do: https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L1478 so when it use prepared sql-statement with parameters prepared by parent (`AbstractEntityInheritancePersister::prepareInsertData()` reuse `BasicEntityPersister::prepareInsertData()` reuse `BasicEntityPersister::prepareUpdateData()` with `$isInsert` mode): https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L640-L659 we get error from database, e.g. postgresql: ``` DOException: SQLSTATE[08P01]: <<Unknown error>>: 7 ERROR:  bind message supplies 4 parameters, but prepared statement "" requires 6 ``` So fixed `JoinedSubclassPersister::getInsertColumnList()`. There is no such error for update queries, because parent methods used in `JoinedSubclassPersister::update()`: `BasicEntityPersister::prepareUpdateData()` and `BasicEntityPersister::updateTable()`. 1. There were problems with logic to update entity properties with database values in generated columns (`notInsertable`|`notUpdatable`|`version`) after flush - `JoinedSubclassPersister::assignDefaultVersionAndUpsertableValues()`: https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php#L548-L555 - flag which activates it (`ClassMetadataInfo::$requiresFetchAfterChange`) in both cases ([executeInserts()](https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php#L170-L171) and [update()](https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php#L224-L235)) doesnt inherited from entity parent-class. This fixed by tracking of parent mappings in `ClassMetadataInfo::addInheritedFieldMapping()` like it done for child entity in `mapField()` (may be add setter for [factory](https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php#L105-L108)): https://github.com/doctrine/orm/blob/da9b9de5906802cab1c71f59ffd9fba53ed4011d/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php#L2814-L2820 - it use parent select query to get generated columns, while it could be in both tables (child and parent), so override query builder in persister - `JoinedSubclassPersister::fetchVersionAndNotUpsertableValues()` - where added join (reuse `JoinedSubclassPersister::getJoinSql()`) and column aliases. Make parent `extractIdentifierTypes()` and `$identifierFlattener` make them protected. - because generated column may be in child tables logic should be after insert into child tables in persister `insert()` method to avoid `LengthException('Unexpected empty result for database query.')`. 1. For functional tests added `JoinedInheritanceRoot` entity, with children for each case and `JoinedInheritanceChild` to test root entity columns. Declare database default column values to avoid platform-specific `columnDefinition`. Use `generated: 'ALWAYS'` in hope to obtain error from `update()` method
admin added the pull-request label 2026-01-22 16:14:10 +01:00
admin closed this issue 2026-01-22 16:14:11 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#12479