Я пытался сопоставить многоуровневое наследование с doctrine2, вот UML: введите здесь описание изображения

Каждый класс отображает таблицу SQL, отображение выглядит следующим образом:

   /**
     * @Entity
     * @Table(name="PERSONS")
     * @InheritanceType("JOINED")
     * @DiscriminatorColumn(name="PERSON_TYPES", type="string")
     * @DiscriminatorMap({"INSUREE" = "Insuree", "ADMIN" = "Admin"})
     */
    abstract class Person extends Entity{}

    /**
     * @Entity
     * @Table(name="INSUREES")
     * @InheritanceType("JOINED")
     * @DiscriminatorColumn(name="INSUREE_TYPES", type="string")
     * @DiscriminatorMap({"CUSTOMER" = "Customer", "THIRD_PARTY" = "ThirdParty"})
     */
    abstract class Insuree extends Person{}

    /**
     * @Entity
     * @Table(name="ADMINS")
     */
    final class Admin extends Person implements User{}

    /**
     * @Entity
     * @Table(name="CUSTOMERS")
     */
    final class Customer extends Insuree implements User{}

    /**
     * @Entity
     * @Table(name="EXPERTS")
     */
    final class Expert extends Person{}

Когда я пытаюсь найти всех клиентов или любые другие конкретные классы, я получаю эту ошибку:

Uncaught Doctrine \ Instantiator \ Exception \ InvalidArgumentException: предоставленный класс "Insuree" является абстрактным и не может быть создан в ...

Я нашел проект на github, иерархия отображения которого похожа на мою и отлично работает:

https://github.com/paulandrieux/MultipleInheritanceSandbox/tree/master/src/Acme/DemoBundle/Entity

РЕДАКТИРОВАТЬ :

После помещения всех дискриминаторов в верхний класс (Person) Doctrine пропускает вставку данных в таблицу INSUREES, когда я пытаюсь сохранить нового клиента, поскольку я получаю эту ошибку:

Возникла исключительная ситуация при выполнении 'INSERT INTO CUSTOMERS (ID, ID_CARD, SEPA) VALUES (?,?,?)' С параметрами [10, "", ""]: SQLSTATE [23000]: Нарушение ограничения целостности: 1452 Невозможно добавить или обновить дочернюю строку: ограничение внешнего ключа не выполняется (aaa. customers, CONSTRAINT customers_ibfk_1 FOREIGN KEY (ID) ССЫЛКИ INSUREES (ID ) НА КАСКАДЕ УДАЛЕНИЯ) "

Вот мой sql-скрипт CREATE TABLE:

CREATE TABLE IF NOT EXISTS PERSONS(
  ID INTEGER NOT NULL  AUTO_INCREMENT,
  LAST_NAME VARCHAR(25) NULL,
  FIRST_NAME VARCHAR(25) NULL,
  ADDRESS VARCHAR(25) NULL,
  CITY VARCHAR(25) NULL,
  ZIP_CODE BIGINT(5) NULL,
  TEL VARCHAR(13) NULL,
  PERSON_TYPES ENUM("ADMIN","EXPERT","THIRD_PARTY","CUSTOMER"),
  MAJ TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (ID)
 );

CREATE TABLE IF NOT EXISTS INSUREES(
  ID INTEGER NOT NULL  UNIQUE,
  BONUS_MALUS REAL(5,2) DEFAULT 1.0,
  FOREIGN KEY (ID) REFERENCES PERSONS(ID) ON DELETE CASCADE
);


CREATE TABLE IF NOT EXISTS THIRD_PARTIES(
  ID INTEGER NOT NULL  UNIQUE,
  COMPAGNY VARCHAR(128) NULL,
  FOREIGN KEY (ID) REFERENCES INSUREES(ID) ON DELETE CASCADE
 );


CREATE TABLE IF NOT EXISTS EXPERTS(
  ID INTEGER NOT NULL UNIQUE,
  RANK BIGINT(4) NULL,
  FOREIGN KEY (ID) REFERENCES PERSONS(ID) ON DELETE CASCADE
)comment = "";

 CREATE TABLE IF NOT EXISTS CUSTOMERS(
  ID INTEGER NOT NULL UNIQUE,
  ID_CARD VARCHAR(100),
  SEPA VARCHAR(100),
  FOREIGN KEY(ID) REFERENCES INSUREES(ID) ON DELETE CASCADE
);

 CREATE TABLE IF NOT EXISTS ADMINS(
   ID INTEGER NOT NULL UNIQUE,
   ROLE VARCHAR(128) NULL, 
   FOREIGN KEY (ID) REFERENCES PERSONS(ID) ON DELETE CASCADE
 );
-1
Aleks 4 Янв 2017 в 11:06
Тот внешний пример, который вы нам показали, отличается, потому что они не используют базовый класс в качестве таблицы в базе данных. Вы в своем коде используете базовые классы также как таблицы в базе данных, поэтому у вас есть ошибки.
 – 
nospor
4 Янв 2017 в 13:45
Каждый класс аннотируется @Entity.
 – 
Aleks
4 Янв 2017 в 13:55
Проверьте свои аннотации и его. Они разные, поверьте;) И он не строит запросы с абстрактными сущностями.
 – 
nospor
4 Янв 2017 в 14:04
Можете ли вы опубликовать запрос или как вы пытаетесь найти, например все клиенты? Наследование выглядит нормально
 – 
Sepultura
4 Янв 2017 в 17:24

1 ответ

Лучший ответ

Вам разрешено определять InheritanceType, DiscriminatorColumn и DiscriminatorMap только в самом верхнем классе Доктрина наследования таблиц-классов, которое в вашем случае является Человеком .

Я бы посоветовал следующее:

   /**
     * @Entity
     * @Table(name="PERSONS")
     * @InheritanceType("JOINED")
     * @DiscriminatorColumn(name="PERSON_TYPES", type="string")
     * @DiscriminatorMap({
            "INSUREE" = "Insuree", 
            "ADMIN" = "Admin",
            "CUSTOMER" = "Customer",
            "EXPERT" = "Expert"
        })
     */
    abstract class Person extends Entity{}

    /**
     * @Entity
     * @Table(name="INSUREES")
     */
    abstract class Insuree extends Person{}

Обновить:

Ваша схема базы данных должна выглядеть примерно так: database-scheme где interface_task - это человек в вашем случае. Вы делаете это со всеми своими дочерними классами (и дочерними-дочерними классами), все они указывают на суперкласс, а идентификатор - это внешний ключ, указывающий на идентификатор суперкласса interface_task (человек в вашем случае)

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

1
Sepultura 5 Янв 2017 в 20:24
Я изменил отображение таким образом, казалось, что оно работает нормально, пока я не создал клиента; Запрос Doctrine Insert пропускает таблицу INSUREES и действует следующим образом: вставьте персональные данные -> вставьте данные клиента, поскольку я получаю хорошее нарушение ограничения целостности.
 – 
Aleks
5 Янв 2017 в 20:03
Вам нужна таблица для каждой сущности, каждая таблица имеет внешний ключ, указывающий на идентификатор вашего самого верхнего класса (Person) с каскадом при удалении
 – 
Sepultura
5 Янв 2017 в 20:13
Я только что обновил свой вопрос: я добавил сценарий создания таблицы.
 – 
Aleks
5 Янв 2017 в 20:48
Извините, что ответил так поздно, но я, наконец, решил проблему, сделав это. Сначала у меня были ошибки ограничений MySQL, потому что я выполнял наследование mysql так же, как и наследование ООП: таблица Insurees имела внешний ключ, указывающий на лиц и клиентов, а у сторонних сторон был один, указывающий на страховщиков, в то время как они, должно быть, также указывали на лиц.
 – 
Aleks
14 Янв 2017 в 16:30