Symfony2 + Doctrine + Herencia (dudas)

TeNSHi

Hola, en el proyecto de symfony que estoy haciendo (básicamente es un foro) y tengo un par de dudas.

La primera, tengo digamos que varios tipos de topics dependiendo del foro en el que estén, por ejemplo el formulario para un nuevo topic en el foro de coches:

  • Titulo Tema
  • Mensaje Tema
  • Caballos motor coche
  • Litros deposito

Para el foro de bicicletas:

  • Titulo Tema
  • Mensaje Tema
  • Anchura rueda bicicleta
  • Platos

Ahora mismo en una única entidad Topic tendría todos los campos, es decir:

  • Titulo
  • PrimerMensaje (es una entidad post)
  • UltimoMensaje (es una entidad post, el ultimo realizado en el topic)
  • Caballos
  • LitrosDeposito
  • AnchuraRuedaBici
  • PlatosBici

Y claro me queda en la base de datos una única tabla topics con muchos campos a NULL debido a que dependiendo del foro hay campos que no necesito, me imagino que el peso de estos campos NULL no sera muy grande pero es posible que con muchos topics la cosa cambie, además supongo que aunque mínimo tendrá un coste al hacer consultas.

Como no estaba seguro de que fuese la mejor me puse a buscar y encontré esto:

7.2. Single Table Inheritance

Que si no entiendo mal seria hacer una superclase con todos los campos en común y luego hacer subclases que hereden de ella y añadan los campos que necesitan, quedando así:

Entidad Topic:

  • Titulo
  • PrimerMensaje (es una entidad post)
  • UltimoMensaje (es una entidad post, el ultimo realizado en el topic)

Entidad CocheTopic:

  • Caballos
  • LitrosDeposito

Entidad BiciTopic:

  • Caballos
  • LitrosDeposito

La duda que tengo es si realmente es mejor así, me parece mas ortodoxo, pero tengo miedo por el tema de rendimiento:

7.2.2. Performance impact

Como lo veis mejor? esta ultima forma de hacerlo? perderé mucho rendimiento o merece la pena?

La segunda duda que tengo es que como veis en la entidad Topic, guardaría las entidades de tipo post primerMensaje y ultimoMensaje, que como las variables describen son el primer y el ultimo mensaje del tema. Mi duda es, realmente las necesito? necesitar las necesito, pero no se si seria mejor sacarlas haciendo una consulta mas (puede que trayéndolas cuando en un query solicite el topic) o dejarlas así, opiniones?

P.D.: Siento si he puesto demasiado tocho, era para que quedara claro lo que quiero y las dudas.

Merkury

#1 Un campo null ocupara un espacio minimo.

De todas formas tu entidad topic tiene un fallo.

  • Caballos
  • LitrosDeposito
  • AnchuraRuedaBici
  • PlatosBici

Como dices esto deberías abstraerlo en forma de una relacion 1 - n o n - n si quieres tener varios hacia una tabla/s donde tengas los tipos haciendo que la entidad topic no tenga campos null o campos que nunca vas a utilizar y creando asi la relacion o coleccion de atributos.

Pero no es una "superclase" con todos los campos en plan $litrosDeposito o $caballos será una clase donde tengas $atributosTopic y ahi tendras una lista con todos relacionadas tambien al tipo de subforo en el que los puedes usar... no se si me estoy explicando XD.

Te dejo un diagrama:

1 respuesta
TeNSHi

#2 Gracias por el comentario, respecto a lo segundo? mas que nada es porque tengo la sensación de que podría estar duplicando datos en la base de datos, pero no se si merece la pena para aligerar las consultas.

1 respuesta
Merkury

#3 El diagrama debería esclarecer tus dudas XD.

Dependiendo de que tipo de en que foro este podrás seleccionar unas u otras categorias y así tienes todo limpito y ordenado.

Categorías no es mas que una tabla en la que almacenar las diferentes cosas que quieres asociar y en función de que.

#3 Fuck la relacion de Topic - TipoForo es 1-n, no n-n

TeNSHi

Vale releyendo tu edit y la documentación creo que ya entiendo lo que comentas. Yo estaba mirando para aplicar 7.2. Single Table Inheritance que lo único que hace es tener mas "ordenadas" las entidades pero a nivel de base de datos obtendría exactamente lo mismo, es decir seguiría con los mismos campos NULL, no?

Si no te he entendido mal y por la documentación de doctrine para eliminar los NULL tendría que usar 7.3. Class Table Inheritance que a nivel de entidades (clases) seria similar pero en la base de datos ya no lo tendría todo en una misma tabla si no que lo tendría dividido según como tenga hecha las clases. Es decir tendría algo así?:

<?php
namespace MyProject\Model;

/**
 * @Entity
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="discr", type="string")
 * @DiscriminatorMap({"topic" = "Topic", "bicitopic" = "BiciTopic", "cochetopic" = "CocheTopic"})
 */
class Topic
{
    private $id;
	
	private $titulo;
	
	private $primerMensaje;
	
	private $ultimoMensaje;
}

/** @Entity */
class BiciTopic extends Topic
{
    private $caballos;
	
private $litrosDeposito;
}

/** @Entity */
class CocheTopic extends Topic
{
    private $anchuraRuedaBici;
	
private $platosBici;
}

El tema es que por lo que veo en la documentación cada vez que consultes un tema hay que hacer al menos un JOIN, por eso esto cuando lo leí lo había medio descartado, tu que opinas? XD

Respecto al diagrama que me pones TipoForo seria TipoTopic (BiciTopic, CocheTopic)?, y lo de categoría entiendo que es para saber a que tipo de foro pertenece (coches, bici, normal)? si esta ultima pregunta es afirmativa yo lo que hago es en la vista tengo un boton para crear temas que ejecuta una ruta a la que le paso ya el slug del foro (/crear-tema/foro-bici = /crear-tema/{forumSlug}) y ya en el controlador dependiendo del slug pasado creo un Topic, un BiciTopic o un CocheTopic por lo que en principio no me haría falta almacenarlo.

Y una duda mas (siento ser tan pesado XD) en su momento me surgió la duda de como debían ser los controladores para hacerlos lo menos pesados posibles, lo único que encontré es que cuanto mas pequeños mejor (lógico supongo XD).
Pero si por ejemplo en el controlador que te acabo de explicar (en el que creo el tema) tengo que estar comprobando en que foro se quiere crear el tema para en función de eso crear un tipo de tema u otro, es mejor hacer un action para cada tipo de foro para no tener que hacer ese tipo de comprobaciones? en plan newTopicAction, newBiciTopicAction, newCocheTopicAction.

Otra vez gracias y siento ser tan cansino XD

Merkury

Yo tengo una pregunta antes de seguir... ¿Que sabes de diseño de bases de datos? Porque parece que no sepas lo que estas haciendo y explicarte como crear una estructura de datos eficiente sin que tengas conocimientos es muy complicado.

Respecto a los JOIN con mi diagrama no necesitas hacerlo, porque los datos hay una propagación de FK y una tabla intermedia para la n - n.

Respecto a los controladores realmente si tienes una buena estructura de datos, pasando el objeto topic con sus propiedades al hacer el persist todo lo demas iria solo.

Como he dicho si no manejas diseño de BBDD y tal, leer la documentacion de Doctrine lo unico que va a hacer es confundirte más, porque Doctrine esta pensado para quien sabe de BBDD.

1 respuesta
TeNSHi

#6 Se podría decir que no es mi fuerte la verdad. El tema es que en el diagrama que me has puesto no se exactamente que campos irían en cada tabla y puede que por eso me cueste ver exactamente lo que me estas proponiendo.

1 respuesta
Merkury

#7 Igual antes de meterte con Symfony y Doctrine como ORM deberías darle un repaso a diseño y planificacion de BBDD Relacionales... porque por mucho que te ayudemos sin eso, no vas a poder completar el proyecto.

1 respuesta
TeNSHi

#8 A ver no digo que no tenga ni idea, digo que no es mi fuerte. La cuestión es que no se si he acabado de entender el ejemplo que me pusiste antes.

1 respuesta
Merkury

#9 A ver que no lo digo en plan malas, pero en serio si no has entendido el ejemplo, dale un repasito.

Basicamente el ejemplo consiste en que tu tienes un Topic que pertenece a un tipo de foro y que tiene una coleccion de atributos (tamaño rueda, deposito, lo que sea) dependiendo del tipo de foro, pero estos atributos no se guardan en la entidad Topic, si no que se generan en la relación con los tipos/attr/llamaloX.

Los campos que necesitas en cada tabla pues eso ya dependerá, pero basicamente necesitaras una propagacion de FK de tipo foro a topic y posiblmente de la relacion topic tipos/attr/llamaloX se te generará una tabla intermedia con las dos PK de cada tabla.

1 respuesta
kraneok

Vamos a ver, si tiramos un poco de inteligencia y enfrentamos las supuestas tablas

  • Titulo Tema
  • Mensaje Tema
  • Caballos motor coche
  • Litros deposito

Para el foro de bicicletas:

  • Titulo Tema
  • Mensaje Tema
  • Anchura rueda bicicleta
  • Platos

Vemos que ambas tienen el mismo número de campos. Sin importarnos realmente, el nombre del campo y orientando la atención al valor que contiene, en vez de llamar a los dos últimos campos: Caballos motor coche, Litros depósito y Anchura rueda bicicleta, Platos, podrían pasar perfectamente a tener un nombre mas genérico y que se pueda relacionar con el topic en si, por ejemplo: Atributo1 y Atributo2.

Es decir, el tópic siempre va a tener un Título tema, un Mensaje tema y Atributo1 y Atributo2.

Como cuando tu trabajes al nivel que sea, ya sabes eso ( y lo documentas además ), no debería haber ningún tipo de problema.

1 respuesta
TeNSHi

#10 Ahora ya he entendido mejor el ejemplo, cuando acabe de instalar FOSUserBundle me pondré con ello.

#11 A ver era un ejemplo para explicarlo lo mas fácil posible, realmente tengo mas campos y diferente numero de campos para cada tipo de topic, ademas que no todos los campos son del mismo tipo o al menos no todo son pares del mismo tipo con lo cual me seguirían quedando campos a NULL, vamos si te he entendido bien porque hoy estoy espesito.

Gracias a ambos!!

Usuarios habituales

  • TeNSHi
  • kraneok
  • Merkury