Mapeo de Herencia Las Tres Estrategias Hibernate soporta las tres estrategias básicas de mapeo de herencia: tabla por jerarquía de clases tabla por subclase tabla por clase concreta En adición, Hibernate soporta un cuarto, ligeramente diferente tipo de polimorfismo: polimorfismo implícito Es posible usar estrategias de mapeo diferentes para diferentes ramificaciones de la misma jerarquía de herencia, y entonces usar polimorfismo implícito para conseguir polimorfismo a través de toda la jerarquía. Sin embargo, Hibernate no soporta la mezcla de mapeos <subclass>, y <joined-subclass> y <union-subclass> bajo el mismo elemento <class> raíz. Es posible mezclar juntas las estrategias de tabla por jerarquía y tabla por subclase, bajo el mismo elemento <class>, combinando los elementos <subclass> y <join> (ver debajo). Tabla por jerarquía de clases Supón que tenemos una interface Payment, con los implementadores CreditCardPayment, CashPayment, ChequePayment. El mapeo de tabla por jerarquía se vería así: ... ... ... ... ]]> Se requiere exactamente una tabla. Hay una gran limitación de esta estrategia de mapeo: las columnas declaradas por las subclases, como CCTYPE, no pueden tener restricciones NOT NULL. Tabla por subclase Un mapeo de tabla por sublclase se vería así: ... ... ... ... ]]> Se requieren cuatro tablas. Las tres tablas de subclase tienen asociaciones de clave primaria a la tabla de superclase (de modo que en el modelo relacional es realmente una asociación uno-a-uno). Tabla por subclase, usando un discriminador Observa que la implementación de Hibernate de tabla por subclase no requiere ninguna columna discriminadora. Otros mapeadores objeto/relacional usan una implementación diferente de tabla por subclase que requiere una columna discriminadora de tipo en la tabla de superclase. Este enfoque es mucho más difícil de implementar pero discutiblemente más correcto desde un punto de vista relacional. Si quisieras usar una columna discriminadora con la estrategia de tabla por subclase, puedes combinar el uso de <subclass> y <join>, como sigue: ... ... ... ... ]]> la declaración opcional fetch="select" dice a Hibernate que no recupere los datos de la subclase ChequePayment usando una unión externa (outer join) al consultar la superclase. Mezclando tabla por jerarquía de clases con tabla por subclase Puedes incluso mezclar las estrategias de tabla po jerarquía y tabla por subclase usando este enfoque: ... ... ... ... ]]> Para cualquiera de estas estrategias de mapeo, una asociación polimórfica a la clase raíz Payment es mapeada usando <many-to-one>. ]]> Tabla por clase concreta Podríamos ir de dos maneras a la estrategia de mapeo de tabla por clase concreta. La primera es usar <union-subclass>. ... ... ... ... ]]> Están implicadas tres tablas. Cada tabla define columnas para todas las propiedades de la clase, inccluyendo las propiedades heredadas. La limitación de este enfoque es que si una propiedad es mapeada en la superclase, el nombre de columna debe ser el mismo en todas las tablas de subclase. (Podríamos relajar esto en un lanzamiento futuro de Hibernate.) La estrategia de generador de indentidad no está permitida en la herencia de unión de subclase, de hecho la semilla de clave primaria tiene que ser compartida a través de todas las subclases unidas de una jerarquía. Tabla por clase concreta, usando polimorfismo implícito Un enfoque alternativo es hacer uso de polimorfismo implícito: ... ... ... ]]> Nota que en ningún sitio mencionamos la interface Payment explícitamente. Nota además que las propiedades de Payment son mapeadas en cada una de las subclases. Si quieres evitar duplicación, considera usar entidades XML. (por ejemplo, [ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] en la declaración DOCTYPE y &allproperties; en el mapeo). La desventaja de este enfoque es que Hibernate no genera UNIONs de SQL al realizar consultas polimórficas. Para esta estrategia de mapeo, una asociación polimórfica a Payment es mapeada generalmente usando <any>. ]]> Mezclando polimorfismo implícito con otros mapeos de herencia Hay una cosa más por notar acerca de este mapeo. Ya que las subclases se mapean cada una en su propio elemento <class> (y ya que Payment es sólo una interface), cada una de las subclases podría ser parte de otra jerarquía de herencia! (Y todavía puedes seguir usando consultas polimórficas contra la interface Payment.) ... ... ... ... ]]> Una vez más, no mencionamos a Payment explícitamente. Si ejecutamos una consulta contra la interface Payment - por ejemplo, from Payment - Hibernate devuelve automáticamente instancias de CreditCardPayment (y sus subclases, ya que ellas también implementan Payment), CashPayment y ChequePayment pero no instancias de NonelectronicTransaction. Limitaciones Existen ciertas limitaciones al enfoque de "polimorfismo implícito" en la estrategia de mapeo de tabla por clase concreta. Existen limitaciones algo menos restrictivas a los mapeos <union-subclass>. La siguiente tabla muestra las limitaciones de mapeos de tabla por clase concreta, y de polmorfismo implícito, en Hibernate. Funcionalidades de mapeo de herencia Estrategia de herencia muchos-a-uno polimórfica uno-a-uno polimórfica uno-a-muchos polimórfica mushos-a-muchos polimórfica load()/get() polimórficos Consultas polimórficas Uniones polimórficas Recuperación por unión externa (outer join) tabla por jerarquía de clases <many-to-one> <one-to-one> <one-to-many> <many-to-many> s.get(Payment.class, id) from Payment p from Order o join o.payment p soportada tabla por subclase <many-to-one> <one-to-one> <one-to-many> <many-to-many> s.get(Payment.class, id) from Payment p from Order o join o.payment p soportada tabla por clase concreta (union-subclass) <many-to-one> <one-to-one> <one-to-many> (para inverse="true" solamente) <many-to-many> s.get(Payment.class, id) from Payment p from Order o join o.payment p soportada tabla por clase concreta (polimorfismo implícito) <any> no soportada no soportada <many-to-any> s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult() from Payment p no suportadas no soportada