我创建了一个现有Id
的新实体,我想更新相关的数据库记录。
学说merge 是我最好的朋友:识别是否有更改并生成正确的更新查询。
$entity = new Entity();
$entity->setId(1);
$entity->setName('test');
$EntityManager->merge($entity);
$EntityManager->flush();
假设db中已存在id = 1的元素:如果名称与'test'不同,则Doctrine会生成此查询:
UPDATE table SET name = ? WHERE id = ? ["test","1"]
如果我再次运行上面的代码,Doctrine会识别出没有任何更改,也没有提交任何查询。
但是...... 当我设置DateTime字段时,Doctrine认为它已更改并始终运行更新查询:
$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"]
你知道一种避免这种无用更新的方法吗?谢谢!
答案 0 :(得分:7)
正如@Raymond所说,这是预期的行为。
很遗憾,但如果您的合并不依赖date
属性,则解决方法可能是在合并后设置日期,如下所示:
$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();
<强>更新强>
尝试之后,唯一的选择似乎是检索合并对象并通过再次刷新EntityManager来更新它。
您可以使用:
$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 强>
我发现在合并后实现更新的更清洁的方式是重新合并实体,例如:
$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
但这并没有改变主要问题并且没有意义,因为你无法自己比较DateTime
对象,$entity->getDate()
在调用{{1}之前返回null即使在第一次合并之后也是如此。
Doctrine通过引用(哈希)将对象与setDate
进行比较,即使对象日期未更改,===
的新实例也会导致更新。
这是一个真正有问题的问题,可以通过使用\DateTime
作为比较运算符来修复,但是教条不能在不打破其通用对象比较机制的情况下为==
创建特定条件,涉及降低最常用功能之一的性能。
答案 1 :(得分:6)
显然,它似乎是Doctrine中的一个仍未解决的错误(参考Github)
这是预期的行为,通过引用比较对象