JPA: especificar el esquema de base de datos en tiempo de ejecución con EclipseLink

octubre 25, 2015
0

EclipseLinkDurante el ciclo de vida de una aplicación Java EE es común que se despliegue en diferentes entornos antes de llegar al entorno de producción. No sólo varían las máquinas en las que se despliega la aplicación, sino también los servidores de bases de datos.

Si nuestra aplicación web o enterprise usa el API JPA para el acceso a datos, es posible que en algunas circunstancias sea necesario especificar el catálogo o el esquema de base de datos en la anotación @Table de nuestras entidades.

¿La razón? En ciertas bases de datos, como por ejemplo Oracle, el usuario que utilizamos para la conexión no es el propietario del esquema. Por esta razón, al generar las consultas SQL es preciso especificar un «qualifier» para referirnos al catálogo o al esquema al que pertenecen las tablas.

La siguiente consulta en una base de datos Oracle funciona sólo si el usuario con el que realizamos la consulta es el propietario del esquema:

select id, name from customer; 

Para realizar la misma consulta con un usuario diferente (con permisos de lectura), debemos especificar el nombre del esquema:

select id, name from mycrm.customer;

A la hora de definir nuestra entidad JPA, podemos indicar el nombre del esquema:

@Entity
@Table(name = "customer", schema = "mycrm")
public class Customer implements Serializable {

De esta forma, el problema queda corregido… en principio.

Recientemente, en uno de nuestros clientes nos hemos encontrado con el siguiente problema: existen tres entornos y en cada entorno, aunque las tablas son las mismas, el nombre del esquema varía, por lo que la solución anterior no es válida. Llegados a este punto existen varias soluciones:

  • Generar un archivo de despliegue por cada entorno: no es una solución demasiado buena. Obliga a modificar la propiedad «schema» en la anotación @Table antes de generar el archivo de despligue para cada entorno.
  • Obtener el nombre del esquema mediante un archivo de propiedades y establecerlo en tiempo de ejecución. No existe una solución estándar para esto y depende de la implementación de JPA que usemos.

Si la implementación que usamos es EclipseLink, la solución consiste en implementar el interfaz SessionCustomizer, mediante la cual es posible modificar los metadatos de una unidad de persistencia.

public class MySessionCustomizer implements SessionCustomizer {

    private final String schema;
    
    public MySessionCustomizer() {
        schema = <obtener el nombre del esquema de un archivo de propiedades>;
    }
    
    @Override
    public void customize(Session session) throws Exception {
        session.getLogin().setTableQualifier(schema);
    }
    
}

El último paso consiste en añadir una propiedad en nuestra unidad de persistencia indicando que se usará nuestro SessionCustomizer:

<properties>
    <property name="eclipselink.session.customizer" value="com.cygnussource.MySessionCustomizer"/>
</properties>

Si decidimos usar esta solución, ya no es necesario especificar el esquema en las entidades:

@Entity
@Table(name = "customer")
public class Customer implements Serializable {

Es necesario recordar que esta solución sólo aplica cuando usamos EclipseLink. En el caso de Hibernate, también existe una solución, aunque es distinta. Hablaremos de ella en futuras entradas.

2015 © Cygnus Source S.L.