Doctrine merge: DateTime field always updated

北战南征 提交于 2019-12-30 05:57:09

问题


I create a new Entity with an existing Id, and I want to update the related database record.

Doctrine merge has been my best friend: recognizes if there are changes and generates the correct update query.

$entity = new Entity();
$entity->setId(1);
$entity->setName('test');
$EntityManager->merge($entity);
$EntityManager->flush();

Suppose that the element with the id=1 already exists in the db: if the name is different from 'test', Doctrine generates this query:

UPDATE table SET name = ? WHERE id = ? ["test","1"]

If I run again the code above, Doctrine recognizes that nothing is changed, and no query is committed.

But... when I set a DateTime field, Doctrine consider it as changed and always runs the update query:

$entity = new Entity();
$entity->setId(1);
$entity->setDate(new \DateTime(2000-01-01));
$EntityManager->merge($entity);
$EntityManager->flush();
//* ALWAYS commits this query:
>> UPDATE table SET date = ? WHERE id = ? ["2000-01-01 00:00:00","1"]

Do you know a way to avoid this useless update? Thanks!


回答1:


As said by @Raymond, it's the expected behavior.

It's a pity, but if your merge doesn't depend on the date property, a workaround could be to set the date after the merge like this:

$entity = new Entity();
$entity->setId(1);
// Set all fields that the merge is depending on
// ...
$EntityManager->merge($entity);

$entity->setDate(new \DateTime('2000-01-01'));
$EntityManager->flush();

Update

After tried, the only alternative seems to retrieve the merged object and update it by flushing the EntityManager again.

You can use:

$entity = new Entity();
$entity->setId(1);
// Set all fields that the merge is depending on
$EntityManager->merge($entity);
$EntityManager->flush();

$entity = $EntityManager->getRepository('Your\Entity')->find(1); // Retrieve the entity
$entity->setDate(new \DateTime('2000-01-01'));
$EntityManager->flush(); // Reflush

Update2

The cleaner way I found to achieve the update after the merge is re-merge the entity, e.g. :

$entity = new Entity();
$entity->setId(1);
// Set all fields that the merge is depending on
$EntityManager->merge($entity); // The real merge that retrieve (without commit) or create
$EntityManager->flush();

$entity->setDate(new \DateTime('2000-01-01'));
$entityManager->merge($entity); // Remerge the object with the changed field
$EntityManager->flush(); // Working re-flush

But this doesn't change the main problem and doesn't really make sense because you cannot compare the DateTime object by yourself, $entity->getDate() return always null before calling setDate, even after the first merge.

Doctrine compare the objects by reference (hash) with ===, also a new instance of \DateTime causes the update even if the object date is unchanged.

This is a really problematic issue that could be fixed by using == as comparison operator, but doctrine can't make a specific condition for \DateTime without breaking their generic object comparison mechanism, that involves to decrease performances of one of the most used feature.




回答2:


Apparently it's seems to be a bug in Doctrine which is still not resolved(Reference Github)

That is expected behavior, objects are compared by reference



来源:https://stackoverflow.com/questions/35603737/doctrine-merge-datetime-field-always-updated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!