Доктрина 2 Наследование конкретных таблиц с ассоциациями

Я прочитал Doctrine 2 Inheritance Mapping с Ассоциацией, но скажите, если вам нужно Animal быть самостоятельной сущностью, скажем, для создания списков опций.

В этом случае столбец дискриминатора для Pet находится в колонке видов в animal table,

Схема базы данных домашних животных

Так что классы будут примерно такими.

class Animal
{
    $id;
    $species;
}

/**
 * @Table(name="animal")
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="species", type="string")
 * @DiscriminatorMap({"dog" = "Dog", "cat" = "Cat"})
 */
abstract class Pet
{
    $id
    $species;
}

class Dog extends Pet { }

class Cat extends Pet { }

class Owner 
{
    /**
     * @OneToMany(targetEntity="Pet")
     */
    $pets
}

Я вижу пару проблем.

  1. animal таблица не имеет внешнего ключа к owner, Так что$pets Ассоциация не собирается работать.

  2. Animal а также Pet более или менее то же самое. Если кто-то что-то меняет в Animal эти изменения не будут отражены ни в одном Pet подклассы.

Возможным решением первой проблемы было бы иметь дополнительную таблицу с именем pet, но есть еще проблема с ассоциацией, потому что столбец дискриминатора все еще находится в animal таблица и дублирование столбца в pet нарушит нормализацию.

1 ответ

Я не уверен, что полностью понимаю вашу проблему, но я попробую:

  • Pet быть Animal, имеет смысл сделать это явным в вашей иерархии классов. Обратите внимание, что абстрактный класс Pet может подкласс конкретного класса Animal, Таким образом, вы все еще можете создать экземпляр Animal, Dog или Cat, но вы не можете создать экземпляр Pet;
  • Animal Корневой класс может иметь свое собственное значение дискриминатора, что позволяет сохранить его с помощью Doctrine. Затем вы можете создать и сохранить Dog или Catи даже общий Animal;
  • Animal нужна ссылка на своего владельца;
  • Owner теперь имеет отношение один ко многим Animal;
  • species Столбец является дискриминатором и не добавляет значения в модель вашего домена (имя класса сообщит вам, какой Animal Вы имеете дело с), поэтому я бы посоветовал удалить это свойство.

Последнее замечание, вам действительно нужно Pet учебный класс? Если у питомца нет ничего конкретного Animal (т.е. класс пуст), тогда вы, вероятно, должны удалить его из иерархии классов.

class Owner {
    /**
     * @OneToMany(targetEntity="Animal")
     */
    protected $animals;
}

/**
 * @Table(name="animal")
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="species", type="string")
 * @DiscriminatorMap({"animal" = "Animal", "dog" = "Dog", "cat" = "Cat"})
 */
class Animal {
    /** @Id @Column(type="integer") @GeneratedValue */
    protected $id;

    /** @ManyToOne(targetEntity="Owner") */
    protected $owner;
}

abstract class Pet extends Animal {
    // Do you really need this class?
}

class Dog extends Pet {
    // ...
}

class Cat extends Pet {
    // ...
}

Что касается структуры вашей базы данных, я предлагаю следующие изменения:

  • Переехать owner_id от Dog & Cat к Animal Таблица;
  • Удалить animal_id от Dog & Cat столы; они поделятся id значение с Animal стол (один на один).
Другие вопросы по тегам