maphe
maphe

Reputation: 1931

Design entity model to manage multiple bidirectionnal relations

I'm trying to find the best way to design relations between entities from my model.

Imagine the following Doctrine 2 entities:

class ImageHistory
{
    /**
     * @var Image
     */
    protected $current;

    /**
     * @var \Doctrine\Common\Collections\Collection
     */
    protected $old;
}

class Dog
{
    protected $name;

    /**
     * @var ImageHistory
     */
    protected $imageHistory;
}

class Cat
{
    protected $name;

    /**
     * @var ImageHistory
     */
    protected $imageHistory;
}

I would like to establish two one-to-many bidirectional Doctrine relations where Cat and Dog are the owning sides of the relations. Both Cat and Dog classes have this entity configuration:

manyToOne:
    imageHistory:
        targetEntity: ImageHistory
        joinColumn:
            name: image_history_id
            referencedColumnName: id

How to represent the other side of te relation ?

oneToMany:
    owner:
        targetEntity: <What can I write here?>
        mappedBy: imageHistory

I imagine a solution where Cat and Dog inherite an Animal entity class, so I can move the ManyToOne relation into the Animal class and put Animal as targetEntity of the OneToMany relation. But the problem reappears if I have a new SoundHistory entity and: Cat, Dog and new Car and Boat classes must have a relation to it.

A can't just add SoundHistory as oneToMany relation to the Animal class because Car and Boat won't inherite from it. So I still can't fill the targetEntity of my OneToMany relation in the ImageHistory entity.

What is the best way to design the entity model in this case?

Upvotes: 19

Views: 361

Answers (2)

Okspen
Okspen

Reputation: 42

The best way to do what you need is use a separate join table to represent the relations between Cat, Dog and ImageHistory, SoundHistory. For this you can use one to many unidirectional mapping with join table. Doctrine docs found here, thanks to NaeiKinDus: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/association-mapping.html#one-to-many-unidirectional-with-join-table

The point is - image & sound histories are stored independently and the join table cat_image_history stores which Cat owns which ImageHistory. So Doctrine will get your cat's id, check the cat_image_history and get the correct ImageHistory by image_history_id. Same way you can add SoundHistory only for dogs or for both cats and dogs.

The mapping can look something like this:

Cat:
  type: entity
  manyToMany:
    imageHistory:
      targetEntity: ImageHistory
      joinTable:
        name: cat_image_history
        joinColumns:
          cat_id:
            referencedColumnName: id
        inverseJoinColumns:
          image_history_id:
            referencedColumnName: id
            unique: true

Upvotes: 0

Leon Husmann
Leon Husmann

Reputation: 684

A Many-To-One Relation is unidirectional, so you can't represent the other side.

Also, you should consider creating a super entity, if you really want to store the Dogs and Cats in the same table.

Upvotes: 0

Related Questions