Allow way to clear cached persisters on UnitOfWork #6854

Closed
opened 2026-01-22 15:40:06 +01:00 by admin · 2 comments
Owner

Originally created by @Jasonoro on GitHub (Oct 11, 2021).

Feature Request

Q A
New Feature yes
RFC no
BC Break no (depending on implementation)

Summary

Currently, when calling clear() on a UnitOfWork, the cached persisters aren't cleared, nor is there any other way of clearing this cache. However, clearing this cache is needed in some scenario's. Most commonly, it is needed after setting the class metadata manually, for example when (temporarily) switching from an assigned ID to a manual ID [1] [2]. For example, the following code fails:

class User {
    	/**
	 * @ORM\Id()
	 * @ORM\GeneratedValue()
	 * @ORM\Column(type="integer")
	 */
	public $id;

	/**
	 * @ORM\Column(type="string", length=100)
	 */
	public $username;
}


$user = new User();
$user->username = 'Test'
$manager->persist($user);
$manager->flush();

// I now want to insert a User with a specific ID (for example, during a data fixture or database migration)

$metadata = $manager->getClassMetadata(User::class);
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE);
$metadata->setIdGenerator(new AssignedGenerator());
$user = new User();
$user->id = 100;
$user->username = 'Test2'
$manager->persist($user);
$manager->flush(); //ERROR: Since the `persister` was still cached here,
// during the insert an insert is done without the `id` field but WITH the `100` value,
// so there is a mismatch between the paramters and the fields to insert.

The above code would work fine if the persisters field would be cleared. As such, I see two options:

  1. Clear the field when calling UnitOfWork->clear(). To make the above code work by inserting a simple $manager->clear(). However, in theory this could break BC, if someone is relying on the caching logic somehow.
  2. Introduce a separate clearPersisters() method. This would not BC break, but looks very out-of-place and wouldn't be my preferred solution.

I can make a PR for this, but some discussion about whether we want to clear this cache might be good first.

Originally created by @Jasonoro on GitHub (Oct 11, 2021). ### Feature Request <!-- Fill in the relevant information below to help triage your issue. --> | Q | A |------------ | ------ | New Feature | yes | RFC | no | BC Break | no (depending on implementation) #### Summary Currently, when calling `clear()` on a `UnitOfWork`, the cached `persisters` aren't cleared, nor is there any other way of clearing this cache. However, clearing this cache is needed in some scenario's. Most commonly, it is needed after setting the class metadata manually, for example when (temporarily) switching from an assigned ID to a manual ID [[1]](https://www.generacodice.com/en/articolo/1141047/explicitly-set-id-with-doctrine-when-using-8220-auto-8221-strategy) [[2]](https://athlan.pl/how-to-set-id-doctrine2/). For example, the following code fails: ```php class User { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ public $id; /** * @ORM\Column(type="string", length=100) */ public $username; } $user = new User(); $user->username = 'Test' $manager->persist($user); $manager->flush(); // I now want to insert a User with a specific ID (for example, during a data fixture or database migration) $metadata = $manager->getClassMetadata(User::class); $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE); $metadata->setIdGenerator(new AssignedGenerator()); $user = new User(); $user->id = 100; $user->username = 'Test2' $manager->persist($user); $manager->flush(); //ERROR: Since the `persister` was still cached here, // during the insert an insert is done without the `id` field but WITH the `100` value, // so there is a mismatch between the paramters and the fields to insert. ``` The above code would work fine if the `persisters` field would be cleared. As such, I see two options: 1. Clear the field when calling `UnitOfWork->clear()`. To make the above code work by inserting a simple `$manager->clear()`. However, in theory this could break BC, if someone is relying on the caching logic somehow. 2. Introduce a separate `clearPersisters()` method. This would not BC break, but looks very out-of-place and wouldn't be my preferred solution. I can make a PR for this, but some discussion about whether we want to clear this cache might be good first. <!-- Provide a summary of the feature you would like to see implemented. -->
admin closed this issue 2026-01-22 15:40:06 +01:00
Author
Owner

@beberlei commented on GitHub (Oct 29, 2021):

This is not a supported use case to modify the metadata at runtime. Can you explain what you are using this for? I am inclined to close this, because its really causing havoc to do this. Maybe you should create a custom id generator?

@beberlei commented on GitHub (Oct 29, 2021): This is not a supported use case to modify the metadata at runtime. Can you explain what you are using this for? I am inclined to close this, because its really causing havoc to do this. Maybe you should create a custom id generator?
Author
Owner

@Jasonoro commented on GitHub (Nov 22, 2021):

Apologies for the late reaction, missed the comment.

The use case for this is that normally the id is auto-assigned. However, when migrating an old database over to a new one, the old records need to keep their original ID, while after that step some new records are inserted that have a auto-generated ID. As such, the above code was created (and the bug was found).

Looking back on it, it might be a better idea to make a custom ID generator that auto-generates if there is no ID set, and if there is an ID set it just takes that one. That might just be a better solution here.

If this isn't supported, feel free to close the issue. A small note in the documentation might however be useful, as these are all public methods.

@Jasonoro commented on GitHub (Nov 22, 2021): Apologies for the late reaction, missed the comment. The use case for this is that normally the id is auto-assigned. However, when migrating an old database over to a new one, the old records need to keep their original ID, while after that step some new records are inserted that have a auto-generated ID. As such, the above code was created (and the bug was found). Looking back on it, it might be a better idea to make a custom ID generator that auto-generates if there is no ID set, and if there is an ID set it just takes that one. That might just be a better solution here. If this isn't supported, feel free to close the issue. A small note in the documentation might however be useful, as these are all public methods.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6854