Mapeo de una relación Uno a Uno-o-Cero en Hibernate

La creación de los mapas de Hibernate incluyen muy seguido la creación de relaciones de una propiedad de una clase hacia un único objeto de otra clase mapeada. Un ejemplo de esto está en el siguiente extracto de mapas:

<many-to-one name="responsable" column="PERS_CDG"
            not-null="false"></many-to-one>

El ejemplo corresponde a un Proyecto que tiene un responsable.

Este mapeo indica que la clase en cuestion tiene una propiedad responsable que es una instancia de la clase Persona. Al otro lado, en persona, probablemente tendremos algo como

 <bag name="proyectos" inverse="false">
     <key column="PERS_CDG" />
     <many-to-many column="PROY_CDG" />
 </bag>

Este último extracto define una lista de proyectos para una persona. Como puede apreciarse, corresponde al inverso de la relación con respecto al primer extracto presentado.

Relación uno a uno-o-cero

La dificultad está cuando este mismo efecto se busca relacionando con un sólo elemento en ambos lados de la relación. En el ejemplo, esto sucedería si se deseara que cada Persona pudiera tener a cargo sólo un proyecto.

En este caso, puede utilizarse el elemento <one-to-one> de Hibernate. Este, según lo probado, funciona correctamente cuando podemos suponer que siempre un proyecto tendrá un responsable. Si esto no se da, Hibernate lanzará una excepción indicando que un campo no ha sido encontrado. Todo esto, por cierto, cuando tratamos de abrir el campo responsableen modo lazy.

 

Solución

El mapeo correcto considera, por el lado del Proyecto (siguiendo con el ejemplo) el uso de un <many-to-one> efectivamente, ya que siempre nos entregará un sólo objeto.

Por el otro lado, debemos usar un <one-to-one>, pero no debemos especificar la columna de la que debe salir el dato del Proyecto para este responsable. Simplemente dejamos que Hibernate haga la deducción desde el inverso de la relación. Esto puede ser algo más caro, pero es la solución encontrada que más se ajusta al diseño de clases del proyecto en construcción.

Entonces, los mapas quedan de la siguiente manera:

<many-to-one name="responsable" 
          column="PERS_CDG" unique="true" cascade="all" />

y por el lado de la persona:

<one-to-one name="proyecto" 
     constrained="true" property-ref="responsable"/>

La clave está en la propiedad property-ref, que indica cuál es el campo del lado del Proyecto que debe verificarse para generar internamente la consulta que permitirá obtener los responsables. Sin este indicador, Hibernate no sabe por donde hacer el cruce, lanzando el error de no encontrar el campo.