Forcing Doctrine to Persist

I stumbled upon a case where Doctrine would refuse to persist my entity due to a very special circumstance. Here’s the context: I’m using a generic method in my Repository to fetch a Post. I’m selecting partial fields like this:

If the entity is found, then I proceed to delete it by setting is_deleted to true, persisting and then flushing:

It doesn’t save the entity. It skips it entirely. The column is mapped though. The problem is that the UnitOfWork checks the new data against the originally loaded data, then skips the fields that were not originally loaded. This seems to be the intended behavior. This in turn causes the whole entity to be skipped. I even tried selecting the column as HIDDEN (a DQL keyword), still no luck. In contrast, if I were to update the “name” property, it would have saved, because it was loaded in the SELECT.

Thankfully, the UnitOfWork has a public method that deals with it:

The hash refers to the specific instance, then you provide the mapped property name and the value. The value must be different from the one that you’re setting later, otherwise it will also be skipped. Call this just before setting/persisting/flushing and you’re in business.

8 thoughts on “Forcing Doctrine to Persist

  1. At first I thought PARTIALS could be the cause. But at the bottom line it is the way Doctrine detects changes with the UnitOfWork:

    The same scenario makes lifecycle callbacks like preUpdate fail too btw.

    Interesting fact that HIDDEN didn’t work either. So the column doesn’t get mapped at all and is only used for the DQL to execute the query?

    • HIDDEN’s purpose is generally to compute a value to be used as sorting. Example: … AS score HIDDEN … ORDER BY score. So it makes sense that it won’t be in the original data.

      I think the reason partials have this update issue is because they were meant for reading operations, but not for writing back. Although it would make sense to *not* load all the data if you’re overriding everything anyway, like when you receive data through an API. Perhaps ->persist($entity, $force_update) or something of the sort would be useful.

      Or perhaps the Doctrine team has a better idea of how to merge JSON data into an entity.

  2. nimasdj

    When data is not changed why do you need to persist it again?

    • Data is changed, but Doctrine does not see it as changed. It’s all in the article.

  3. When you say

    The value must be different from the one that you’re setting later, otherwise it will also be skipped.

    Do you mean that you are setting the value of is_deleted on that entity to false then calling

    and that the change in the property value will trigger the fact that it will be taken into account for the persist call ?

    • Yes. I set it to false using setOriginalEntityProperty, then set it to true normally. Note that setting it to false normally, without going through the setOriginalEntityProperty method, will cause the entity to not be saved.

  4. Tgabi333

    If you call $post->setIsDeleted(true) would load the full entity and after that doctrine would catch the change, isn’t it?

    • It doesn’t load the full entity when you do that. In any case, when loading a partial, it makes no sense to then load the full entity. That would defy the point of loading a partial.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">