多个数据库的Hibernate实体 [英] Hibernate Entities from Multiple Databases

查看:83
本文介绍了多个数据库的Hibernate实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的数据模型在两个数据库上分为模式。除了在两者之间桥接的几个单键关系之外,这些模式是单独使用的。没有写入交易将跨越两个数据库。

Our data model is separated into schemas on two databases. The schemas are used in isolation except for a few single-key relationships that bridge between the two. There are no write transactions that will span both databases.

与此问题类似执行使用Hibernate 在不同的数据库中连接2个表,我们希望使用Hibernate来处理连接实体。我们不能使用数据库解决方案(DB2上的联合视图)。

Similar to this question Doing a join over 2 tables in different databases using Hibernate, we want to use Hibernate to handle joining the entities. We cannot use the database solution (Federated views on DB2).

我们已经使用两个单独的数据库配置(Doctor和Patient)设置了Hibernate,

We have set up Hibernate with two separate database configurations (Doctor and Patient), which works perfectly when using DAOs to explicitly access a particular session.

我们希望在调用 DoctorBO.getExam()。getPatient()时使用Hibernate自动检索实体。 其中检查包含指向其他数据库上的Patient表的ID。

We want to use Hibernate to automatically retrieve the entity when we call DoctorBO.getExam().getPatient() Where examination contains an id pointing to the Patient table on the other database.

我尝试这样做的一种方法是使用自定义UserType :

One way I've tried doing this is using a custom UserType:

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;

UserType工作 - 数据被正确加载,只有字段的Id持久保存到数据库。我测试了 doctor.getExam()。getPatient() doctor.getExam()。setPatient()和两个似乎工作很好,但我认为这是一个可怕的黑客,我没有足够的知识Hibernate,知道这是否安全使用。

The UserType works - the data is loaded correctly with only the Id of the field persisted to the database. I have tested very simple examples of doctor.getExam().getPatient() and doctor.getExam().setPatient() and both seem to work great, however I think this is a terrible hack and I do not have adequate knowledge of Hibernate to know if this is safe to use.

有没有更好的方式来实现我们想要的?

Is there a better way to achieve what we want? Is the way I've described here adequate, or will it cause difficulties in the future?

推荐答案

我不认为这是正确的一个好主意。你试图使仿佛一切都在一个单一的数据库,而事实并非如此。虽然不是一个真正的关联,但你让好像在考试和病人之间有一个真实的 toOne 关联。

I don't think it's a good idea. You're trying to make "as if" everything was in a single database, whereas it's not the case. And you make "as if" there was a real toOne association between an exam and a patient, although it's not a real association.

虽然你意识到这个事实,其他或未来的开发人员不一定会,并且会想知道为什么不可能进行查询,例如

Although you are conscious of this fact, other or future developers won't necessarily be, and will wonder why it's not possible to make a query such as

select e from Exam e left join fetch e.patient

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

简而言之,你的伪关联只能满足一个常规协会提供的合同的一小部分,这将会导致更多的混乱比起舒适。

In short, your pseudo-association only fulfills a very small part of the contract a regular association offers, and this will, IMO, cause more confusion than comfort.

没有什么阻止你使用像

Patient getExamPatient(Exam e)

做同样的事情,两个实体之间的真实关联。

that does the same thing, but makes it clear that there is no real asociation between both entities.

这篇关于多个数据库的Hibernate实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆