2009-04-16 3 views
7

Я новичок в hibernate, как вы скоро увидите. Я прошу прощения, если у этого вопроса есть легкий ответ, но я просто недостаточно знаком со всей терминологией, чтобы найти его легко.Полиморфизм гибернации: создание правильного класса

Предположим, у меня есть базовый класс «A» и один подкласс «B», который я сопоставляю с Hibernate, возможно, используя таблицу для каждой стратегии подкласса. Базовый класс не абстрактный. Все B - это As, но не все As are Bs. Это отражено в базе данных, где таблица таблиц B ссылается на таблицу A.

Хорошо, теперь предположим, что у меня есть программа, которая отображает список объектов A. Пользователь может выбрать любой объект A и перейти на экран, чтобы изменить его ... НО, если объект A также является B, экран позволит пользователю изменить B вместо A.

Как в В мире я к этому подхожу?

Примечание: Я не спрашиваю, как определить, какой класс является объектом. Я спрашиваю, как получить hibernate для возврата списка объектов, которые относятся к классу.

+0

Вы спрашиваете, как сделать наследование? http://www.hibernate.org/hib_docs/v3/reference/en-US/html/inheritance.html Можете ли вы более конкретно узнать о трудностях, с которыми вы сталкиваетесь с документацией? – erickson

+0

Я немного ознакомился с отображением наследования и признал стратегию «таблица за подкласс» возможной. То, что я не понял, заключается в том, что запрос суперкласса будет возвращать объекты подкласса ... который я не нашел для примера кода во время моего непродолжительного поиска. Огромное спасибо! – Boden

ответ

6

Приносим извинения за этот вопрос. Я очень удивлен, как работает спящий режим, это действительно здорово. Я не думал, что это сделает все это автоматически, и я действительно даже не был уверен, что я пытался спросить. Когда я ответил на комментарии, я начал усовершенствовать этот вопрос в своей голове и смог затем найти ответ, который я искал. Спасибо всем, кто помог.

Ответ: hibernate делает это автоматически.

Предположим, у вас есть в вашей базе данных таблицы А с первичным ключом «ид», и таблицы B, которая имеет первичный ключ с именем «a_id», который ссылается на таблицу А.

Таким образом, вы создаете следующие классы (сокращенную):

public class A { 
    private String aProperty; 
    // ... getter and setter, etc 
{ 

public class B extends A { 
    private String bProperty; 
    // ... getter and setter, etc 
} 

Затем сопоставить их следующим образом:

<hibernate-mapping> 
    <class name="A" table="a" catalog="testokdelete"> 
     <id name="id" type="java.lang.Integer"> 
      <column name="id" /> 
      <generator class="identity" /> 
     </id> 
     <property name="aProperty" column="a_property"/> 
     <joined-subclass name="B" table="b"> 
      <key column="a_id"/> 
      <property name="bProperty" column="b_property"/> 
     </joined-subclass> 
    </class> 
</hibernate-mapping> 

и вы можете вернуть объекты а и в с помощью простого «из» запроса, как показано в следующем коде:

Query query = session.createQuery("from A"); 
List<Object> objects = query.list(); 
for (Object object: objects) { 
    System.out.print("A property: "); 
    System.out.print(((A)object).getAProperty()); 
    System.out.print(", B property: "); 
    System.out.println((object.getClass() == B.class) ? ((B)object).getBProperty() : "not a B"); 
} 

Все это делает возвращает список объектов с помощью запроса «из А», а затем проходит через них распечатывание aProperty из нашего класса А и, если класс типа В, bProperty от нашего B класса.

Запрос на спящий режим в этом случае является автоматически полиморфным и даст вам объект B, если это необходимо.

+1

Да, Hibernate делает это. Но использование (object.getClass() == B.class)? ((B)) является RTTI. Вам не нужно это делать, и это говорит о том, что ваши классы плохо разработаны. – tpdi

+0

Это выглядит как простой код отладки. Это не обязательно означает, что «реальные» классы будут использоваться таким образом. Однако иногда требуется RTTI, и в этих случаях правильной идиомой для тестирования является «object instanceof B», а не 'object.getClass() == B.class'. – erickson

2

Вы можете использовать RTTI с экземпляром, но это не объектно-ориентированное.

Вместо дать базовый класс, A метода, относящиеся к каким дополнительным B делает, например, если A является Customer и B является PreferredCustomer, метод может быть isPreferredCustomer().

В A метод возвращает false, в B возвращается.

Важно отметить, что мы не спрашиваем, имеет ли объект определенный класс; мы задаем бизнес-вопрос, задавая объект, если он может что-то сделать. Это тонкое, но важное различие.

В частности, это означает, что ваш код ниже не изменится, если и если вы добавите дополнительные подклассы Customer, если каждый подкласс правдиво отвечает на вопрос, isPreferredCustomer().

В коде:

if(a.isPreferredCustomer()) { 
    showPreferredCustomerPage(a) ; 
else { 
    show CustomerPage(a); 
} 

Вы можете подумать, что еще лучше, чтобы дать Customer метод showPage(), но слишком сильно связывает свои модели с представлениями.

Вместо этого вы помещаете вышеуказанный код в некоторый класс ViewDispatcher, который может быть ортогональным с Заказчиком и его подклассами.

Например, у вас может быть несколько подклассов ViewDispatcher, некоторые из которых заботятся о PreferredCustomer и некоторых, которые этого не делают.

+0

Хороший вопрос, чтобы не путаться с типами в бизнес-логике - никогда не думал об этом раньше. +1 –

+0

Но в этом случае A ничего не знает о B. Нет свойств A, либо в классе, либо в таблице, отображаемой, которая указывает, является ли A также B. – Boden

+1

. Одна точка подкласса должна быть возможность добавлять дополнительные функции в класс без необходимости изменения базового класса. Это решение мутирует A с деталями B. Что происходит, когда вы получаете C, который имеет другой тип клиента. Теперь вам нужно изменить isPreferredCustomer, и он не является логическим. – digitaljoel

1

Хорошо, я собираюсь предположить, что у вас есть соответствующие классы. Если вы сделаете это, вы должны быть в состоянии сделать следующее, я думаю:

public List<A> getAllClassA(){ 
     Session session = HibernateUtil.getSession(); 
     Criteria criteria = session.createCriteria(A.class); 

     List<A> ret = criteria.list(); 

     return ret; 
} 

Если вы не знакомы с критериями, его довольно просто подобрать. Этот фрагмент кода будет извлекать все объекты класса A из базы данных. Если вы правильно настроили карту, я думаю, что Hibernate также будет поддерживать атрибуты B ваших объектов A, если они на самом деле являются объектами B (извините, если это сбивает с толку).

Сообщите мне, если это был, если вы ищете, или если вам нужен код для HibernateUtil.

Смежные вопросы