2012-01-24 14 views
9

Nuestro modelo de datos está separado en esquemas en dos bases de datos. Los esquemas se usan de forma aislada, excepto por unas pocas relaciones de llave única que se conectan entre los dos. No hay transacciones de escritura que abarquen ambas bases de datos.Entidades de hibernación de múltiples bases de datos

Similar a esta pregunta Doing a join over 2 tables in different databases using Hibernate, queremos utilizar Hibernate para gestionar la unión de las entidades. No podemos usar la solución de base de datos (vistas federadas en DB2).

Hemos configurado Hibernate con dos configuraciones de base de datos separadas (Doctor y paciente), que funciona perfectamente cuando se utilizan DAO para acceder explícitamente a una sesión en particular.

Queremos utilizar Hibernate para recuperar automáticamente la entidad cuando llamamos al DoctorBO.getExam().getPatient() Donde el examen contiene una identificación que apunta a la tabla del paciente en la otra base de datos.

Una forma que he intentado hacer esto es usar un UserType personalizado:

public class DistributedUserType implements UserType, ParameterizedType 
{ 
    public static final String CLASS = "CLASS"; 
    public static final String SESSION = "SESSION"; 

    private Class<? extends DistributedEntity> returnedClass; 
    private String session; 

    /** {@inheritDoc} */ 
    @Override 
    public int[] sqlTypes() 
    { 
     // The column will only be the id 
     return new int[] { java.sql.Types.BIGINT }; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public Class<? extends DistributedEntity> returnedClass() 
    { 
     // Set by typedef parameter 
     return returnedClass; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public boolean equals(Object x, Object y) throws HibernateException 
    { 
     if (x == y) 
     { 
      return true; 
     } 

     if ((x == null) || (y == null)) 
     { 
      return false; 
     } 

     Long xId = ((DistributedEntity) x).getId(); 
     Long yId = ((DistributedEntity) y).getId(); 

     if (xId.equals(yId)) 
     { 
      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public int hashCode(Object x) throws HibernateException 
    { 
     assert (x != null); 
     return x.hashCode(); 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException 
    { 
     Long id = rs.getLong(names[0]); 
     return HibernateUtils.getSession(session).get(returnedClass, id); 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException 
    { 
     DistributedEntity de = (DistributedEntity) value; 
     st.setLong(index, de.getId()); 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public Object deepCopy(Object value) throws HibernateException 
    { 
     return value; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public boolean isMutable() 
    { 
     return false; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public Serializable disassemble(Object value) throws HibernateException 
    { 
     return (Serializable) value; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public Object assemble(Serializable cached, Object owner) throws HibernateException 
    { 
     return cached; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public Object replace(Object original, Object target, Object owner) throws HibernateException 
    { 
     return original; 
    } 

    /** {@inheritDoc} */ 
    @Override 
    public void setParameterValues(Properties parameters) 
    { 
     String clazz = (String) parameters.get(CLASS); 
     try 
     { 
      returnedClass = ReflectHelper.classForName(clazz); 
     } 
     catch (ClassNotFoundException e) 
     { 
      throw new IllegalArgumentException("Class: " + clazz + " is not a known class type."); 
     } 

     session = (String) parameters.get(SESSION); 
    } 
} 

que luego se utiliza:

@TypeDef(name = "testUserType", typeClass = DistributedUserType.class, parameters = { 
                       @Parameter(name = DistributedUserType.CLASS, value = PatientBO.CLASSNAME), 
                       @Parameter(name = DistributedUserType.SESSION, value = HibernateUtils.PATIENT_SESS) }) 

@Type(type = "testUserType") 
@Column(name = "PATIENT_ID") 
private PatientBO patient; 

El UserType funciona - los datos se cargan correctamente con sólo el Identificación del campo persistido en la base de datos. He probado ejemplos muy simples de doctor.getExam().getPatient() y doctor.getExam().setPatient() y ambos parecen funcionar muy bien, sin embargo, creo que este es un hack terrible y no tengo el conocimiento adecuado de Hibernate para saber si esto es seguro de usar.

¿Hay una mejor manera de lograr lo que queremos? ¿Es adecuada la manera que describí aquí o causará dificultades en el futuro?

+0

+1 para una solución interesante. – Firo

Respuesta

5

No creo que sea una buena idea. Está tratando de hacer que "como si" todo estuviera en una única base de datos, mientras que no es el caso. Y usted hace "como si" hubiera una asociación real toOne entre un examen y un paciente, aunque no es una asociación real.

pesar de que son conscientes de este hecho, otros o futuros desarrolladores no será necesariamente, y se preguntará por qué no es posible hacer una consulta como

select e from Exam e left join fetch e.patient 

o

select e from Exam e where e.patient.name like 'Smith%' 

En resumen, su pseudo-asociación solo cumple una parte muy pequeña del contrato que ofrece una asociación regular, y esto, IMO, causará más confusión que comodidad.

Nada hace que deje de tener un método de utilidad como

Patient getExamPatient(Exam e) 

que hace lo mismo, pero deja claro que no hay una verdadera Asociación entre ambas entidades.

+0

Creo que estaba tratando de ser demasiado inteligente. Esta solución es mejor que la que propuse por las razones que usted indicó. –

Cuestiones relacionadas