Гибернационный полиморфизм: создание правильного класса - PullRequest
7 голосов
/ 16 апреля 2009

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

Допустим, у меня есть базовый класс "A" и один подкласс "B", который я сопоставляю с Hibernate, возможно, используя стратегию таблицы на подкласс. Базовый класс не абстрактный. Все B являются As, но не все As являются B. Это отражено в базе данных, где таблица B ссылается на таблицу A.

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

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

Примечание: я не спрашиваю, как определить, к какому классу относится объект. Что я спрашиваю, так это как получить Hibernate, чтобы вернуть список объектов соответствующего класса.

Ответы [ 3 ]

6 голосов
/ 17 апреля 2009

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

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

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

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

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>

И вы можете вернуть объекты A и B, используя простой запрос "from A", как показано в следующем коде:

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 из нашего класса A и, если класс имеет тип B, bProperty из нашего класса B. 1016 *

Запрос гибернации в этом случае автоматически полиморфен и при необходимости даст вам объект B.

2 голосов
/ 17 апреля 2009

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

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

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

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

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

В вашем коде:

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

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

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

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

1 голос
/ 17 апреля 2009

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

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...