Mapeo objeto-relacional (primera parte)
Agosto 31st, 2005 - [Enlace local]
Hola. Estos días estoy leyendo acerca de Hibernate y con este post voy a empezar una pequeña
serie de “lecciones básicas” que he aprendido sobre el mapeo objeto-relacional. Así
que hablaré de los problemas que surjen en la implementación de la persistencia de POJOs.
Para cualquier aplicación que tenga que lidiar con una base de datos relacional surje un problema.
Tenemos que “casar” el modelo de objetos con el modelo de tablas (modelo relacional). La primera aproximación
es muy sencilla. Por cada clase crearemos una tabla en la que cada fila guardará los datos de un objeto
y cada columna será una propiedad de un objeto.
Veamos un ejemplo. En nuestro modelo de datos tenemos una clase Persona.
Esta es su definición:
import java.util.Date;
import java.io.Serializable;
public class Persona implements Serializable {
private int nif;
private String nombre;
private String apellidos;
private Date fechaNacimiento;
/* métodos get y set */
}
Siguiendo la aproximación
anterior vamos a crear una tabla “personas”. La crearemos así:
CREATE TABLE personas(nif INTEGER, nombre VARCHAR(50), apellidos VARCHAR(50), fecha_nacimiento DATE);
Esto que puede parecer muy sencillo tiene un gran inconveniente. Cuando programamos objetos
usamos punteros/referencias. Para manipular un objeto determinado tenemos que tener
un puntero/referencia que apunte a él. Sin embargo un puntero/referencia sólo existe
mientras el objeto está en memoria y es diferente en cada instancia de la aplicación.
Sin embargo los datos de una base de datos “siempre están allí” y necesitamos una forma de hacer
referencia a ellos de forma unívoca.
Para esta necesidad las bases de datos relacionales cuentan con las archiconocidas claves primarias.
Una clave primaria es un valor de una columna que sirve para identificar de forma unívoca un registro en una tabla.
No existen por tanto dos filas en una tabla que tengan la misma clave primaria.
Debemos elegir un campo del objeto para que sea clave primaria.
En el ejemplo dos personas pueden tener el mismo
nombre, dos personas también pueden tener los mismos apellidos o pueden haber nacido el mismo
día, así que ninguna de estas propiedades nos sirve como clave primaria. Sin embargo dos personas
no pueden tener el mismo NIF. Tenemos un campo del objeto candidato para ser clave primaria.
Toda persona tiene un NIF y no existen dos personas con el mismo NIF.
Ocurre que frecuentemente hay objetos en los que ningún campo puede ser usado como clave primaria.
En esas ocasiones crearemos una columna adicional cuya única finalidad es contener los valores de las
claves primarias. El valor que adquirirá esa columna ya no es proporcionado por el usuario, sino
que será un valor normalmente generado por la base de datos, por ejemplo a través mediante
los “auto_increment” de mysql. O bien puede ser un UUID (identificador único universal):
valor pseudo-aleatorio, que puede ser, por ejemplo, la hora acutual
concatenada con un número aleatorio y a su vez concatenado con la IP del ordenador.
Hay quién siempre usa columnas creadas exclusivamente para contener claves primarias incluso
cuando el objeto contiene un campo que por su naturaleza puede ser clave primaria. Esto es por el lema
“todo valor introducido por el usuario es susceptible de ser cambiado”.
Tras esto voy a volver a escribir la sentencia de creación de la tabla indicando que NIF es clave primaria,
y por ello también indico que no puede ser NULL.
CREATE TABLE personas(nif INTEGER NOT NULL, nombre VARCHAR(50), apellidos VARCHAR(50), fecha_nacimiento DATE, PRIMARY KEY(nif));
Bueno, eso es todo por hoy. No he contado más que perogrulladas pensará alguno.
Cierto, pero esto es sólo el primer post de una mini-serie.
En próximos posts hablaré de las relaciones entre objetos y las claves foráneas. También
hablaré de las diferentes estrategias para mapear jerarquías de herencia. Y finalmente
hablaré de los “objetos de grano fino” (entidades débiles o “fine grained objects”).
Un saludo!