Skip to content

Generated columns with insertable/updatable=false cause false positive change detection #12017

@SherinBloemendaal

Description

@SherinBloemendaal

Bug Report

Q A
Version 3.4.x
Previous Version if the bug is a regression N/A

Summary

Doctrine's UnitOfWork incorrectly detects changes for database-generated columns marked with insertable: false and updatable: false. This causes entities to be scheduled for update even though no actual changes have occurred, which can trigger unwanted events and break change tracking logic.

Current behavior

When an entity has database-generated columns (e.g., GENERATED ALWAYS AS columns) marked with both insertable: false and updatable: false, the UnitOfWork still includes these fields in change detection. This results in:

  • Entities being incorrectly marked as "dirty" and added to $entityUpdates
  • getEntityChangeSet() returning phantom changes like ['generatedField' => [null, DateTimeImmutable]]
  • isScheduledForUpdate() returning true when only generated fields have changed
  • preUpdate events being triggered unnecessarily

Expected behavior

  • Fields marked with insertable: false should not appear in changesets for new entities during INSERT operations
  • Fields marked with updatable: false should not appear in changesets for existing entities during UPDATE operations
  • Entities with only generated field "changes" should not be scheduled for update
  • The UnitOfWork behavior should be consistent with BasicEntityPersister, which already skips these fields

How to reproduce

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'entity_with_generated_fields')]
class EntityWithGeneratedFields
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    public ?int $id = null;
    
    #[ORM\Column(type: 'string')]
    public ?string $name = null;
    
    #[ORM\Column(
        name: 'generated_field',
        type: 'datetime_immutable',
        insertable: false,
        updatable: false,
        columnDefinition: 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP',
        generated: 'ALWAYS'
    )]
    public ?\DateTimeImmutable $generatedField = null;
}

$entity = new EntityWithGeneratedFields();
$entity->name = 'Test Entity';

$em->persist($entity);
$em->flush();

$entity->generatedField = new \DateTimeImmutable();

$uow = $em->getUnitOfWork();
$uow->computeChangeSets();

// Bug: Entity is incorrectly marked as having changes
assert($uow->isScheduledForUpdate($entity) === false); // Fails - returns true
assert($uow->getEntityChangeSet($entity) === []); // Fails - contains generated field

The issue occurs in UnitOfWork::computeChangeSet() and UnitOfWork::recomputeSingleEntityChangeSet() which don't check the notInsertable and notUpdatable field mapping properties during change detection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions