Спящие сущности из нескольких баз данных - PullRequest
9 голосов
/ 24 января 2012

Наша модель данных разделена на схемы в двух базах данных.Схемы используются изолированно, за исключением нескольких взаимосвязей с одним ключом, которые соединяют их.Нет транзакций записи, которые будут охватывать обе базы данных.

Аналогично этому вопросу При объединении двух таблиц в разных базах данных с использованием Hibernate мы хотим использовать Hibernate для обработки объединения сущностей.Мы не можем использовать решение для базы данных (федеративные представления в DB2).

Мы настроили Hibernate с двумя отдельными конфигурациями базы данных («Доктор» и «Пациент»), который отлично работает при использовании DAO для явного доступа к определенному сеансу.

Мы хотим использовать Hibernate для автоматического извлечения сущности, когда мы вызываем DoctorBO.getExam().getPatient() Если обследование содержит идентификатор, указывающий на таблицу Patient в другой базе данных.

Один из способов, которым я пытался это сделать, -используя пользовательский тип пользователя:

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

Что затем будет использоваться:

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

Пользовательский тип работает - данные загружаются правильно, при этом в базе данных сохраняется только Id поля.Я проверил очень простые примеры doctor.getExam().getPatient() и doctor.getExam().setPatient(), и оба, похоже, отлично работают, однако я считаю, что это ужасный хак, и у меня нет достаточных знаний Hibernate, чтобы знать, безопасно ли это использовать.

Есть ли лучший способ достичь того, чего мы хотим?Является ли способ, который я описал здесь адекватным, или это вызовет трудности в будущем?

1 Ответ

6 голосов
/ 09 февраля 2012

Не думаю, что это хорошая идея. Вы пытаетесь сделать «как будто» все было в одной базе данных, тогда как это не так. И вы делаете «как если бы» была настоящая toOne связь между обследованием и пациентом, хотя это не настоящая связь.

Хотя вы знаете об этом факте, другие или будущие разработчики не обязательно будут и будут удивлены, почему невозможно сделать запрос, такой как

select e from Exam e left join fetch e.patient

или

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

Короче говоря, ваша псевдоассоциация выполняет лишь очень небольшую часть контракта, который предлагает регулярная ассоциация, и это, IMO, вызовет больше путаницы, чем комфорта.

Ничто не мешает вам использовать такой служебный метод, как

Patient getExamPatient(Exam e)

, который делает то же самое, но проясняет, что между обеими сущностями нет настоящей ассоциации.

...