Domanda

Il nostro modello di dati è separato negli schemi su due database. Gli schemi sono usati in isolamento ad eccezione di alcune relazioni a chiave singolo che ponteranno tra i due. Non ci sono transazioni di scrittura che abbracciano entrambi i database.

Simile a questa domanda Fare un join su 2 tabelle in diversi database utilizzando Hibernate, vogliamo usare Hibernate per gestire l'adesione alle entità. Non possiamo utilizzare la soluzione di database (viste federate su DB2).

Abbiamo impostato Hibernate con due configurazioni di database separate (medico e paziente), che funziona perfettamente quando si utilizza DAO per accedere esplicitamente a una particolare sessione.

Vogliamo usare Hibernate per recuperare automaticamente l'entità quando chiamiamo DoctorBO.getExam().getPatient() Dove l'esame contiene un ID che punta alla tabella dei pazienti sull'altro database.

Un modo in cui ho provato a farlo è utilizzare un utente personalizzato:

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);
    }
}

Che verrebbe quindi usato:

@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;

UserType funziona: i dati vengono caricati correttamente con solo l'ID del campo persistendo nel database. Ho testato esempi molto semplici di doctor.getExam().getPatient() e doctor.getExam().setPatient() Ed entrambi sembrano funzionare alla grande, tuttavia penso che questo sia un hack terribile e non ho una conoscenza adeguata di Hibernate per sapere se questo è sicuro da usare.

C'è un modo migliore per ottenere ciò che vogliamo? Il modo in cui ho descritto qui è adeguato o causerà difficoltà in futuro?

È stato utile?

Soluzione

Non penso che sia una buona idea. Stai cercando di fare "come se" tutto fosse in un singolo database, mentre non è così. E fai "come se" ci fosse un vero toOne Associazione tra un esame e un paziente, sebbene non sia una vera associazione.

Sebbene tu sia consapevole di questo fatto, gli altri sviluppatori non lo saranno necessariamente e si chiederà perché non è possibile fare una domanda come

select e from Exam e left join fetch e.patient

o

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

In breve, la tua pseudo-associazione soddisfa solo una parte molto piccola del contratto che un'associazione regolare offre e questo, IMO, causerà più confusione che comfort.

Niente ti impedisce di avere un metodo di utilità come

Patient getExamPatient(Exam e)

Questo fa la stessa cosa, ma chiarisce che non esiste una vera asociazione tra le due entità.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top