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

Open
opened 2026-01-22 15:52:57 +01:00 by admin · 1 comment
Owner

Originally created by @SherinBloemendaal on GitHub (Jun 23, 2025).

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.

Originally created by @SherinBloemendaal on GitHub (Jun 23, 2025). ### Bug Report <!-- Fill in the relevant information below to help triage your issue. --> | Q | A |-------------------------------------------- | ------ | Version | 3.4.x | Previous Version if the bug is a regression | N/A #### Summary <!-- Provide a summary describing the problem you are experiencing. --> 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 <!-- What is the current (buggy) 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 <!-- What was the expected (correct) 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 <!-- Provide a failing Unit or Functional Test - you can submit one in a Pull Request separately, referencing this bug report. And if you feel like it, why not fix the bug while you're at it? If that is too difficult, provide a link to a minimal repository containing an application that reproduces the bug. If the bug is simple, you may provide a code snippet instead, or even a list of steps. --> ```php 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.
Author
Owner

@SherinBloemendaal commented on GitHub (Jun 23, 2025):

I seems to only occur for DateTime types (after hydration, a new DateTime object is created). I've created a pull request with reproducer test + possible fix.

@SherinBloemendaal commented on GitHub (Jun 23, 2025): I seems to only occur for DateTime types (after hydration, a new DateTime object is created). I've created a pull request with reproducer test + possible fix.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#7525