Entidades multitabla y tablas multientidad
Voy a hacer un pequeño resumen de la reunión matutina en la que hemos abordado algunos temas pero la mayoría giran en torno al título.
Pensando en el diseño de las entidades de personas (clientes, proveedores...) en Sota y en Vesta (el programa inmobiliario de Berny), mantenemos la idea de hacer herencia (lógico) y añadimos la posibilidad de navegar, que no estaba contemplada, mediante propiedades .ComoCliente, .ComoBanco... que devuelvan una instancia de la entidad actual con el tipo pedido, si existe, y si no null. Se añadirían métodos HacerCliente(), HacerBanco()... para obtener lo mismo pero si no existe, se daría de alta; algo así como dámelo como cliente, y si no existe lo creas y me lo das. Con esto, la idea era eliminar las propiedades EsCliente, EsBanco... y reemplazar su uso por ComoCliente == null, pero al eliminarlas se nos complica el mapeo con la base de datos, ya que allí hay un buleano, así que mientras me decido vamos a hacer esa propiedad internal y vamos a quitar su NP.
Volviendo al tema de esta entrada, esa jerarquía de personas define una tabla multientidad, ya que (en Sota) con una sola tabla Personas almacenamos EPersona (abstracta), ECliente, EProveedor y EAseguradora. ¿Qué nos falta para que esto esté operativo? Como ahora se heredan las propiedades y el atributo Tabla de EPersona, Cargar y Guardar funciona ya en los objetos hijos. En cambio, las colecciones hay que implementarlas manualmente: si pedimos ECliente.GetCollection() hay que establecer un filtro para que sólo devuelva los clientes. Pensamos añadir un atributo a ECliente indicando que usa la tabla Personas pero con un criterio dado (en este caso, cuando el campo EsCliente == TRUE); habrá que pensar cómo definir el criterio, seguramente usando IFiltro. La utilización de este criterio facilitará las colecciones, y también evitará que se cargue incorrectamente un Cliente como Proveedor, por ejemplo (algo que puede suceder actualmente).
No se me ocurre otro caso más complicado donde una misma tabla se emplee para almacenar distintas entidades: aunque no hereden, en ese caso sólo habría que repetir las propiedades en las entidades, y definir la misma tabla al guardar, y el criterio por el que discriminar. El criterio separa lógicamente la tabla en varias subtablas.
Una entidad multitabla, por otro lado, es una entidad que se persiste sobre varias tablas. Vamos a comentar 2 ejemplos muy distintos:
- En Sota, en EPersona hemos almacenado tanto los datos de la persona (física o jurídica) como su dirección. En un futuro, podría plantearse separar esto en dos tablas: Personas y Direcciones. Para no cambiar EPersona, habría que definir que dicha clase se almacena en 2 tablas, de una forma similar a como lo hace Grove pero mejor, claro. La forma de ellos es muy prolija (que bonita traducción para el inglés verbose), y se puede sintetizar bastante.
- Por otro lado, también en Sota tenemos EOrdenBase como raíz común a ECita, EOrden y EPresupuesto. En base de datos tenemos el mismo esquema: las tablas OrdenesBase, Ordenes, Citas y Presupuestos, donde estas 3 referencian a la primera con su campo clave (que también es clave foránea, en este caso no es autonumérico). Al guardar un objeto EOrden, primero hay que guardarlo como EOrdenBase (¿llamando a un base.Guardar? Debe hacerse automáticamente en Nibi.Dal), y una vez guardado hay que guardar las propiedades que existen en EOrden (no las heredadas, ojo) en la tabla definida en EOrden (ojo con que el atributo Tabla se hereda, por lo que EOrden tendrá 2 y sólo hay que coger el propio: parece que sólo hay que coger el heredado cuando no hay un atributo Tabla no heredado; y supongo que el más cercano en la jerarquía). Además, al definir esa tabla hay que indicar que no tiene campo clave autonumérico (que sería posible), sino que su campo clave, y a la vez referencia (clave foránea) al campo clave de EOrdenBase, se llama "Id". Todo esto puede ser una nueva propiedad CampoClaveReferenciaAlPadre="Id" en el atributo Tabla. ¿Se os ocurre un nombre mejor?
- Que una sola entidad se persista en varias tablas (p.ej. EPersona -> Personas y Direcciones).
- Que una jerarquía de entidades se persista en una sola tabla (p.ej. EPersona, ECliente, EProveedor, EAseguradora -> Personas).
- Que una jerarquía de entidades se persista en varias tablas (p.ej. EOrdenBase -> OrdenesBase y EOrden -> Ordenes; o bien EPersona -> Personas y EComprador -> Compradores).
Etiquetas: Nibi.Dal

3 Comments:
Una duda:
Supongamos que la clase EOrden hereda de EOrdenBase pero se va a almacenar en la misma tabla ¿sería necesario añadir un atributo Tabla a EOrden? o solo si EOrden posee alguna propiedad no heredada.
Berny, ese caso es el mismo existente entre EPersona y EAseguradora en Sota: la aseguradora añade 2 campos, pero no vamos a crear una tabla sólo para eso, sino que irán en la misma tabla Personas. De todas formas, seguid proponiendo los casos que se os ocurran por si se nos pasa alguno.
Respecto a si tendrá su propio [Tabla] o no, es una cuestión de diseño, pero creo que haremos que sea necesario: el atributo Tabla no será heredable, y si una entidad quiere persistir, tiene que definirlo explícitamente (aunque herede de otra que ya persiste, no recibirá ese comportamiento). Así podrá indicar en su Tabla:
- la misma tabla que su padre, con lo que se podrán guardar las propiedades propias y heredadas de una tacada.
- otra tabla distinta a la del padre, con lo que surge una cuestión: las propiedades heredadas del padre que tienen campo definido, ¿irán en esta tabla o en la del padre? En nuestros ejemplos iran en la del padre, si en un futuro queremos que no sea así habrá que definir un parámetro del atributo indicando eso. Bueno, y si el padre no tiene atributo Tabla, entonces seguro que las propiedades heredadas deben ir en nuestra tabla. Cuando el padre sí tiene otra tabla, hay que definir en el [Tabla] del hijo un parámetro con el campo de la tabla del hijo que hace referencia al padre, y que lógicamente no es campo de ninguna propiedad (ya que en objetos no necesitamos apuntar al padre puesto que heredamos de él, pero en base de datos sí lo necesitamos, con una clave principal y foránea a la vez.
Dandole vueltas a esa idea de poner en la clase hija un parámetro que indique que campo de la clase padre es su clave foránea, se me ocurre que esto no es estrictametne obligatorio. Me explico:
En nuestro "OM" es obligatorio heredar de una clase base que posee una propiedad Id, por lo tanto estamos obligando a todos los objetos a tener un Id. Teniendo esto como base se podría presuponer que si la tabla de nuestro objeto es distinta a la del objeto padre nuestra propiedad Id es el campo referencia al campo Id del padre. Este es el uso habitual, aunque al introducir esto estamos forzando a que toda tabla del origen de datos tenga una clave primaria Id.
Tras discutirlo Pablo y yo, decidimos, por convención, que lo que propongo sea el comportamiento por defecto pero pudiendo modificarlo con el parámetro del atributo.
Publicar un comentario
<< Home