2012-01-24 16 views
9

Mô hình dữ liệu của chúng tôi được tách thành các lược đồ trên hai cơ sở dữ liệu. Các lược đồ được sử dụng trong sự cô lập ngoại trừ một vài mối quan hệ đơn khóa nối giữa hai lược đồ. Không có giao dịch viết nào sẽ kéo dài cả hai cơ sở dữ liệu.Các đối tượng Hibernate từ nhiều Cơ sở dữ liệu

Tương tự như câu hỏi này Doing a join over 2 tables in different databases using Hibernate, chúng tôi muốn sử dụng Hibernate để xử lý việc tham gia các thực thể. Chúng ta không thể sử dụng giải pháp cơ sở dữ liệu (các khung nhìn liên kết trên DB2).

Chúng tôi đã thiết lập Hibernate với hai cấu hình cơ sở dữ liệu riêng biệt (Doctor and Patient), hoạt động hoàn hảo khi sử dụng DAO để truy cập rõ ràng một phiên cụ thể.

Chúng tôi muốn sử dụng Hibernate để tự động truy xuất thực thể khi chúng tôi gọi DoctorBO.getExam().getPatient() Trường hợp kiểm tra chứa id trỏ đến bảng Bệnh nhân trên cơ sở dữ liệu khác.

Một cách tôi đã cố gắng làm điều này là sử dụng một loại người dùng tùy chỉnh:

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

Mà sau đó sẽ được sử dụng:

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

Các loại người dùng hoạt động - các dữ liệu được nạp một cách chính xác chỉ với Id của trường tồn tại trong cơ sở dữ liệu. Tôi đã thử nghiệm các ví dụ rất đơn giản của doctor.getExam().getPatient()doctor.getExam().setPatient() và cả hai dường như hoạt động tốt, tuy nhiên tôi nghĩ rằng đây là một hack khủng khiếp và tôi không có kiến ​​thức đầy đủ về Hibernate để biết nếu điều này là an toàn để sử dụng.

Có cách nào tốt hơn để đạt được những gì chúng tôi muốn không? Là cách tôi đã mô tả ở đây đầy đủ, hoặc nó sẽ gây ra những khó khăn trong tương lai?

+0

+1 cho giải pháp thú vị. – Firo

Trả lời

5

Tôi không nghĩ đó là một ý hay. Bạn đang cố gắng để làm cho "như thể" tất cả mọi thứ trong một cơ sở dữ liệu duy nhất, trong khi nó không phải là trường hợp. Và bạn thực hiện "như thể" có một mối liên hệ thực sự toOne giữa kỳ thi và bệnh nhân, mặc dù nó không phải là một hiệp hội thực sự.

Mặc dù bạn có ý thức về thực tế này, khác hoặc các nhà phát triển trong tương lai sẽ không nhất thiết phải, và sẽ tự hỏi tại sao nó không thể thực hiện một truy vấn như

select e from Exam e left join fetch e.patient 

hoặc

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

Nói tóm lại, sự liên kết giả của bạn chỉ đáp ứng một phần rất nhỏ của hợp đồng mà một hiệp hội thường xuyên đưa ra, và điều này sẽ, IMO, gây ra nhiều sự nhầm lẫn hơn là sự thoải mái.

Không có gì ngăn bạn khỏi việc có một phương pháp hữu ích như

Patient getExamPatient(Exam e) 

rằng làm điều tương tự, nhưng làm cho nó rõ ràng rằng không có asociation thực giữa hai thực thể.

+0

Tôi nghĩ tôi đã cố gắng quá thông minh. Giải pháp này tốt hơn giải pháp tôi đề xuất vì lý do bạn đã nêu. –