Наследование доктрины для сущностей общих полей

Я использую Zend Framework 3 и Doctrine ORM для своего веб-проекта.

У меня есть несколько модулей в моем приложении (User, Stock, Sales) и некоторые модели сущностей в каждом модуле:

  • User модульные объекты: User, Account, так далее..
  • Stock модульные объекты: SKU, StockLevel, так далее..
  • Sales модульные объекты: Invoice, PaymentMethod, так далее..

По умолчанию все объекты имеют общие поля, например:

  • creationDateTime: Дата / время создания
  • creationUser: Пользователь, создавший объект
  • lastChangeDateTime: Дата / время последнего изменения объекта
  • lastChangeUserПользователь, который последним изменил объект

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

  /**
   * Update the last change fields
   * @param string $user User that is updating 
   */
  public void updateLastChange($user)
  {
      $this->lastChageDataTime = \Datetime();
      $this->lastChangeUser = $user;
  }

Из документации видно, что мне нужно использовать наследование одной таблицы, но я не могу понять, как именно. Вопросы:

a) Используя одиночное наследование таблиц, Doctrine создаст базовую таблицу в базе данных для этих полей или объединит поля базы и сущности для каждой таблицы сущностей, или, другими словами, будет ли у меня только таблица сущностей или это наследство создаст таблица базы данных для базовых полей также?

б) Где я должен поместить свою базовую сущность, чтобы она могла быть унаследована для всех сущностей в другом модуле?

Я был бы признателен, если бы кто-нибудь мог привести пример / ссылки о том, как это сделать

1 ответ

Решение

Для того, что вы хотите сделать, наследование одной таблицы не то, что вам нужно.

Есть 2 варианта:

1) MappedSuperClass (почти прямо из документации)

Вы делаете MappedSuperClass (документацию можно найти в главе 6.1: Сопоставленные суперклассы), и вы добавляете эти общие поля в этот базовый класс. Затем вы расширяете все классы, которым нужны эти поля, из вашего базового (сопоставленного супер) класса.

/** 
 * @MappedSuperclass 
 */
class MappedSuperclassBase
{
    /** @Column(type="datetime") */
    protected $creationDateTime;

    /** 
     * @ManyToOne(targetEntity="Application\Entity\User") 
     * @JoinColumn(name="created_by", referencedColumnName="id")
     */
    protected $creationUser;

    /** @Column(type="datetime") */
    protected $lastChangeDateTime;

    /** 
     * @ManyToOne(targetEntity="Application\Entity\User") 
     * @JoinColumn(name="updated_by", referencedColumnName="id")
     */
    protected $lastChangeUser;

    // ... more fields and methods
}

/** 
 * @Entity 
 */
class EntitySubClass extends MappedSuperclassBase
{
    /** @Id @Column(type="integer") */
    private $id;

    // ... more fields and methods
}

2) Вы используете черту

Вы создаете черту (или несколько отдельных черт для каждого поля / ассоциации), которые вы используете во всех классах, которые должны иметь эти общие поля.

trait BaseTrait
{
    /** @Column(type="datetime") */
    protected $creationDateTime;

    /** 
     * @ManyToOne(targetEntity="Application\Entity\User") 
     * @JoinColumn(name="created_by", referencedColumnName="id")
     */
    protected $creationUser;

    /** @Column(type="datetime") */
    protected $lastChangeDateTime;

    /** 
     * @ManyToOne(targetEntity="Application\Entity\User") 
     * @JoinColumn(name="updated_by", referencedColumnName="id")
     */
    protected $lastChangeUser ;

    // ... more fields and methods
}

/** 
 * @Entity 
 */
class EntitySubClass
{
    use BaseTrait;

    /** @Id @Column(type="integer") */
    private $id;

    // ... more fields and methods
}

Ответы на ваши вопросы:

а) В документах вы можете прочитать:

Наследование отдельных таблиц - это стратегия отображения наследования, когда все классы иерархии отображаются в одну таблицу базы данных. Чтобы определить, какая строка представляет какой тип в иерархии, используется так называемый столбец дискриминатора.

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

Чтобы наследование одной таблицы работало в сценариях, в которых вы используете либо устаревшую схему базы данных, либо самозаписываемую схему базы данных, вы должны убедиться, что все столбцы находятся не в корневом объекте, а в любом из различных дочерних объектов. должен разрешать нулевые значения. Столбцы с ограничениями NOT NULL должны находиться в корневом объекте иерархии наследования одной таблицы.

Такое наследование необходимо только для сущностей, которые во многом похожи и не подходят для примеров, о которых вы говорите в своем вопросе.

б) Вы можете просто добавить базовый объект (так что MappedSuperClass) в общей модели (как ваш Application папка).

Другие вопросы по тегам