Слияние Doctrine: всегда обновляется поле DateTime

Я создаю новый Entity с существующим Id , и я хочу обновить соответствующую запись базы данных.

Doctrine merge был моим лучшим другом: узнает, есть ли изменения и генерирует правильный запрос на обновление.

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

Предположим, что элемент с id = 1 уже существует в db: если имя отличается от «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"] 

Знаете ли вы, как избежать этого бесполезного обновления? Благодаря!

Как сказал @ Раймонд, это ожидаемое поведение.

Жаль, но если ваше слияние не зависит от свойства 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() всегда возвращает null перед вызовом setDate даже после первого слияния.

Doctrine сравнивает объекты по ссылке (hash) с === , также новый экземпляр \DateTime вызывает обновление, даже если дата объекта не изменяется.

Это очень проблематичная проблема, которая может быть исправлена ​​с помощью == качестве оператора сравнения, но доктрина не может создать определенное условие для \DateTime не нарушая их общий механизм сравнения объектов, что связано с уменьшением производительности одной из наиболее используемых функций ,

По-видимому, это похоже на ошибку в Доктрине, которая до сих пор не решена (Reference Github )

Это ожидаемое поведение, объекты сравниваются по ссылке