Доктрина: обновление дискриминатора для SINGLE_TABLE Наследование

С этими классами, как бы вы изменили запись для «Лица» на «Сотрудник».

/** * @Entity * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"}) */ class Person { // ... } /** * @Entity */ class Employee extends Person { // ... } 

Я попытался изменить значение столбца дискриминатора, но я не могу получить к нему доступ. Я также попытался создать экземпляр «Employee» и вручную скопировать данные, но это не работает с автоматически увеличивающимися идентификаторами. Он просто добавляется как новая запись вместо обновления существующего.

Нужно ли писать собственный SQL-запрос или я делаю что-то еще, что в корне неверно?

Это не хороший знак, когда тип экземпляра объекта должен меняться со временем. Я не говорю о понижении / повышении рейтинга здесь, а о необходимости изменить реальный тип объекта.

Прежде всего, позвольте мне сказать вам, почему это плохая идея:

  1. Подкласс может определять больше атрибутов и выполнять некоторую дополнительную работу в его конструкторе. Должен ли мы снова запустить новый конструктор? Что, если он перезаписывает некоторые атрибуты нашего старого объекта?
  2. Что, если вы работаете над экземпляром этого Лица в какой-то части вашего кода, а затем он внезапно превращается в Employee (который может иметь некоторое переопределенное поведение, которого вы не ожидаете) ?!

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

Чаще всего необходимость в этом заключается в плохих объектно-ориентированных проектных решениях.

По этим причинам Doctrine не позволит вам изменить тип объекта объекта. Конечно, вы могли бы написать простой SQL (в конце этого сообщения, но, пожалуйста, прочитайте!), Чтобы сделать изменение в любом случае, но вот два «чистых» варианта, которые я бы предложил:

Я понимаю, вы уже сказали, что первый вариант не был вариантом, но я потратил некоторое время на запись этого сообщения, поэтому я чувствую, что должен сделать его максимально полным для будущей справки.

  1. Всякий раз, когда вам нужно «изменить тип» от Person to Employee , создайте новый экземпляр Employee и скопируйте данные, которые вы хотите скопировать из старого объекта Person, в объект Employee. Не забудьте удалить старый объект и сохранить новый.
  2. Используйте композицию вместо наследования (см. Эту статью в вики, чтобы узнать подробности и ссылки на другие статьи). EDIT: Черт, вот часть приятного разговора с Эрихом Гамма о «Композиции над наследством»!

См. Соответствующие обсуждения здесь и здесь .


Теперь, вот простой метод SQL, о котором я говорил раньше, надеюсь, вам не понадобится его использовать!

Убедитесь, что ваш запрос очищен (так как запрос будет выполнен без какой-либо проверки).

 $query = "UPDATE TABLE_NAME_HERE SET discr = 'employee' WHERE id = ".$entity->getId(); $entity_manager->getConnection()->exec( $query ); 

Вот документация и код метода exec, который находится в классе DBAL\Connection (для вашей информации):

 /** * Execute an SQL statement and return the number of affected rows. * * @param string $statement * @return integer The number of affected rows. */ public function exec($statement) { $this->connect(); return $this->_conn->exec($statement); }