Doctrine2: Owning e inversed side en las relaciones

Estaba escribiendo un post sobre embeber formularios y quería explicar antes cómo funcionaban las relaciones en Doctrine, pero se me estaba haciendo tan largo que he decidido separarlo en uno independiente. En este post veremos uno de los temas importantes que hay que conocer cuando usas Doctrine.

En las relaciones de las Entities siempre hay un lado que es el owning de la relación, ya sea unidireccional o bidireccional. Como vemos en la documentación esto es importante tenerlo claro:

  • Las relaciones pueden ser bidireccionales o unidireccionales.
  • Una relación bidireccional tiene owning side e inversed side.
  • Una relación unidireccional sólo tiene owning side.
  • Doctrine sólo comprobará que ha habido cambios en el owning side.

¿Cuál es el owning y el inversed side?

Depende del tipo de relación:

  • ManyToOne es siempre el owning side de una relación bidireccional.
  • OneToMany es siempre el inversed side de una relación bidireccional.
  • El owning side de una relación OneToOne es la entidad cuya tabla contiene la clave ajena.
  • En las relaciones ManyToMany puedes elegir el owning side que quieras.

¿Cómo se indica en el código?

  • En el mapeo de una declaración OneToOne, OneToMany, o ManyToMany el inversed side tiene que usar el atributo mappedBy, este atributo contiene el nombre del campo asociado en el owning side.
  • En el mapeo de una declaración OneToOne, ManyToOne, or ManyToMany el owning side tiene que usar el atributo inversedBy, este atributo contiene el nombre del campo asociado en el inversed side.

Doctrine sólo comprobará que ha habido cambios en el owning side

¿Qué implica esto? Dado el siguiente ejemplo sacado de la documentación:

Si ejecutamos esto:

Nos avisará que el comentario no se va a persistir por lo que comentábamos antes de que sólo mira que haya cambios en los owning side de las relaciones y como hemos visto antes ManyToOne es siempre el owning side.

Podemos persistir explicitamente el comentario:

O para que sea más fácil podemos indicar en el mapeo que la relación se persista en cascada:

De esta forma con sólo persistir el User se persisten los comentarios.

Pero si tenemos los setters o adders tal cual los genera Doctrine seguiría fallando porque nos diría que el user_id en Comment no puede ser null.

Por lo general es una buena idea y es lo natural gestionar las relaciones dentro de las entities, por ejemplo, cuando se añada un comentario, el método encargado de añadirlo también modifica el comentario para asignarle el propio usuario:

Con esto ya se guardaría el comentario con el usuario que lo ha hecho correctamente. Espero esta semana poder acabar el post sobre formularios embebidos.