I'm using Doctrine 2 as my ORM, and things are going well, but I've been wondering about the EntityManager#persist()
method. The "Persisting entities" documentation says the following about a call to persist()
for object X
:
If X is a preexisting managed entity, it is ignored by the persist operation.
That leads me to believe that persist()
need only be called when the object is new and has not yet been saved to the database. However, the documentation for the "Deferred Explicit" change tracking policy says:
... Doctrine 2 only considers entities that have been explicitly marked for change detection through a call to EntityManager#persist(entity) ...
... which sounds like persist()
must be called on the object for it to be updated at all. When should persist()
be called? If only on new objects, is there a significance performance hit to call it anyway whenever an entity is updated and let Doctrine sort out the difference?
With the Deferred Explicit policy (it's not the default policy), you need to explicitly call persist() on each modified entity for doctrine to persist them. (Except for cascade-persist associations.)
Doctrine still needs to compare the new value of each property with the original value to know which property to update, so this may have a performance hit if you persist()
too much entities.
With the default change tracking policy you only need to call persist on entities that are not yet managed by Doctrine (entities that you created with new
). With this policy, when you call flush() doctrine automatically detects which entities have been updated and need to be persisted.
The documentation is somewhat misleading. In implicit tracking mode, all entities have a state (managed, removed, detached etc.); entities obtained by find()
and similar methods (basically everything which is not created with new
) are already in managed state. On flush()
, all managed (and removed) entites are checked for changes and, if necessary, updated in the DB.
In explicit tracking mode, there is an additional dirty check list, and persist()
adds the object (and possibly associated objects, depending on cascade settings) to that list. Only items on the dirty check list are considered for update. The dirty check list is cleared after flushing, so if you do a second flush, and change the same object again, you must call persist()
once more. (In contrast, the managed state is kept after flush.)
You can check the details for yourself in the Doctrine\ORM\UnitOfWork class; search for isChangeTrackingDeferredImplicit
/ isChangeTrackingDeferredExplicit
(those are the only places where behavior differs under the two policies).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With