来自多个数据库的Hibernate实体

10
我们的数据模型分为两个数据库中的模式。这些模式被单独使用,除了一些在两个数据库之间桥接的单键关系。没有涉及跨越两个数据库的写事务。
与这个问题 Doing a join over 2 tables in different databases using Hibernate 相似,我们想要使用Hibernate来处理实体之间的连接。我们不能使用数据库解决方案(如DB2上的联合视图)。
我们已经为Hibernate设置了两个单独的数据库配置(Doctor和Patient),当使用DAO明确访问特定会话时,它可以完美地工作。
我们想要使用Hibernate在调用DoctorBO.getExam().getPatient()时自动检索实体,其中examination包含指向其他数据库中Patient表的id。
我尝试过的一种方法是使用自定义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()的例子,它们都运行得很好,但我认为这是一种可怕的hack方法,并且我不太了解Hibernate是否安全使用。

有没有更好的方法来实现我们想要的?我描述的方法是否足够好,或者会在未来造成困难?

1个回答

6

我认为这不是个好主意。你试图将所有东西都“仿佛”放入一个数据库中,但这并不是事实。而且你让人们认为一个考试和患者之间有一个真正的toOne关联,虽然实际上并没有。

虽然你已经意识到了这一点,但其他或未来的开发人员可能不会,他们会想知道为什么不能进行如下查询:

select e from Exam e left join fetch e.patient

或者

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

简而言之,您的伪关联仅实现了常规关联提供的非常小的部分合同,这将会导致更多的混乱而不是舒适感。没有任何阻止您拥有像这样的实用方法:
```html

...

```
Patient getExamPatient(Exam e)

这个功能与之前的功能相同,但更清楚地表明两个实体之间没有真正的关联。


我觉得我试图过于聪明了。你所说的原因,这个解决方案比我提出的更好。 - J Barclay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接