Перенести DateTime в базу данных после ее изменения на 30 дней [дублировать]

Многие люди ответили, но никто не упомянул об этом до сих пор ...

Атрибуты используются сильно с отражением.

очень полезно , отмечая ваши пользовательские атрибуты как классы sealed, чтобы улучшить их производительность во время выполнения.

Это также хорошая идея рассмотреть, где было бы целесообразно использовать такой атрибут, и приписать свой атрибут (!), чтобы указать это через AttributeUsage . Список доступных атрибутов может удивить вас:

  • Assembly
  • Модуль
  • Класс
  • Struct
  • Enum
  • Конструктор
  • Метод
  • Свойство
  • Поле
  • Событие
  • Интерфейс
  • Параметр
  • Делегат
  • ReturnValue
  • GenericParameter
  • Все

Также здорово, что атрибут AttributeUsage является частью подписи атрибута AttributeUsage. Whoa для круговых зависимостей!

[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute

18
задан Ocramius 19 March 2013 в 00:47
поделиться

3 ответа

экземпляры DateTime, возвращенные ExampleBundle\Entity\User#getServiceExpiresAt(), - это те же объекты, которые хранятся в самой сущности, которая прерывает инкапсуляцию .

Применяется UnitOfWork в ORM доктрины строгое сравнение для наборов изменений , что в основном означает, что в случае свойств объектов, содержащих объекты, если экземпляр объекта не изменился, ORM не обнаруживает изменения.

При строгом сравнении , верно следующее:

$dateTime1 = new \DateTime('@0');
$dateTime2 = new \DateTime('@0');
$dateTime3 = $dateTime1;

var_dump($dateTime1 !== $dateTime2); // true
var_dump($dateTime1 === $dateTime3); // true

$dateTime1->modify('+1 day');

var_dump($dateTime1 === $dateTime3); // true

Это очень распространенная ошибка среди новичков в программировании ООП, и ее можно быстро решить, установив ваши геттеры и сеттеры, чтобы исходный экземпляр никогда не делился вне вашего объект, как в следующем примере:

public function getServiceExpiresAt()
{
    return clone $this->service_expires_at;
}

public function setServiceExpiresAt(\DateTime $service_expires_at)
{
    $this->service_expires_at = clone $service_expires_at;
}

Это также устранит вашу проблему с помощью Doctrine ORM.

Также обратите внимание, что это устраняет возможные утечки в вашей логике. Например, следующий код ошибочен и трудно отлаживается (при применении ваших сломанных геттеров / сеттеров):

$bankTransaction1 = $someService->getTransaction(1);
$bankTransaction2 = $someService->getTransaction(2);

// leak! Now both objects reference the same DateTime instance!
$bankTransaction2->setDateTime($bankTransaction1->getDateTime());

// bug! now both your objects were modified!
$bankTransaction1->getDateTime()->modify('+1 day');

Итак, независимо от части ORM в вопросе, пожалуйста, не прерывайте инкапсуляцию.

75
ответ дан Ocramius 22 August 2018 в 12:16
поделиться
  • 1
    спасибо за такой подробный ответ. – Laurynas Mališauskas 21 March 2013 в 19:45
  • 2
    Ответ действительно подробный и указывает на точную проблему! Спасибо за попытку. Это сводило меня с ума! – Jan 19 May 2015 в 13:01
  • 3
    Вы должны принять во внимание, что это не очень хорошая идея для всех полей. Если у вас есть связь между двумя объектами, клонирующими объект, вы будете запускать ленивую загрузку, как только вы коснетесь прокси. Это может испортить вашу работу – Nicolas Reynis 29 September 2017 в 15:27
  • 4
    Производительность почти всегда является вторичной в этих сценариях: если вы хотите, чтобы производительность выполнялась из такого рода операций, выполните операцию копирования на уровне DB напрямую (через INSERT ... SELECT ...) – Ocramius 3 October 2017 в 17:33

У меня точно такая же проблема, когда я пытаюсь вставить объект с прошлой датой (я пытаюсь перенести старую базу данных в новую схему с ее данными тоже).

Я попытался клонировать объект как в сеттер, так и в getter, и это бесполезно. Doctrine 2 сохраняет текущую дату. Проверяемая схема, поле - это дата не время штампа, а по умолчанию - значение null.

Как это может быть?

EDIT:

, пожалуйста, извините, внимание, мой коллега Dev добавил событие prePersist:

/**
 * @ORM\PrePersist
 */
function onPrePersist() {
    $this->created_at = new \DateTime('now');
}
0
ответ дан Andrei Sandulescu 22 August 2018 в 12:16
поделиться

С помощью класса DateTimeImmutable рассмотрите свойства даты и времени. Тем самым обратите внимание, что DateTimeImmutable не является экземпляром DateTime .

1
ответ дан Nikola Poša 22 August 2018 в 12:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: