Doctrine 2 Inheritance of Concrete Tables with Associations

I read Doctrine 2 Inheritance Mapping with Association , but I’ll say that if you needed Animal for an independent entity, say, to create option lists.

In this case, the discriminator column for Pet is in the view column in the animal table .

Pet database schema

So the classes will be something like this.

 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 } 

I see a couple of problems.

  • The Animal table does not have a foreign key for owner . Thus, $pets will not work.

  • Animal and Pet more or less the same. If someone changes something in Animal , these changes will not be reflected in any subclasses of Pet .

A possible solution to the first problem would be to have an additional table named Pet , but there is still an association problem, since the discriminator column is still in the Animal table and duplicating the column in Pet will break normalization.

enter image description here

+4
source share
1 answer

I am not sure to fully understand your problem, but I will try:

  • A Pet is Animal , it makes sense to make it explicit in the class hierarchy . Note that the abstract Pet class may subclass a specific Animal class. Thus, you can still create instances of Animal , a Dog or Cat , but you cannot create an instance of Pet ;
  • The root class of Animal can have its own discriminator value , which allows you to save it using Doctrine. Then you can create and save Dog or Cat and even a generic Animal ;
  • Animal requires a reference to its owner ;
  • Owner now has a one-to-many relationship with Animal ;
  • The species column is a discriminator and adds no value to your domain model (the class name will tell you which Animal you are dealing with), so I would advise you to remove this property.

Final note: do you really need a Pet class? If Pet has nothing specific about Animal (i.e., the Class is empty), then you should probably remove it from your class hierarchy.

 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 { // ... } 

Regarding the structure of the database, I propose the following changes:

  • Move owner_id from Dog and Cat to the Animal table;
  • Remove animal_id from the Dog and Cat tables; they will share the id value with the Animal table (one to one).
+3
source

Source: https://habr.com/ru/post/1383031/


All Articles