Как преобразовать ORM в его подкласс, используя Hibernate? - PullRequest
3 голосов
/ 17 января 2011

Например, у меня есть два класса: Person и Employee (Employee является подклассом Person). Персона: имеет фамилию и имя. Сотрудник: также имеет зарплату.

На стороне клиента у меня есть одна HTML-форма, где я могу заполнить информацию о человеке (например, фамилию и имя). У меня также есть «переключатель» между «Персона» и «Сотрудник», и если переключатель включен «Сотрудник», я могу заполнить поле зарплаты.

На стороне сервера сервлеты получают информацию от клиента и используют инфраструктуру Hibernate для создания / обновления данных в / из базы данных. Используемый мэппинг представляет собой единую таблицу для лиц и сотрудников с дискриминатором.

Я не знаю, как преобразовать Person в Employee, изменив его type, который используется как DiscriminatorColumn.

Сначала я попытался:

  • загрузить Персона р из базы данных
  • создать пустой объект Employee e
  • копировать значения из p в e
  • установить значение зарплаты
  • сохранить в базу данных

Но я не смог, так как я также скопировал ID, и поэтому Hibernate сказал мне, что они установили два экземпляра ORM с одинаковым идентификатором.

И я не могу напрямую связать Person с Сотрудником, так как Person является суперклассом Сотрудника.

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

Так что я был бы признателен за любую помощь по этому вопросу:)

Некоторые точности:

Класс человека:

public class Person {

    protected int id;

    protected String firstName;
    protected String lastName;

    // usual getters and setters
}

Класс работника:

public class Employee extends Person {

   // string for now
   protected String salary;

   // usual getters and setters
}

А в сервлете:

// type is the "switch"
if(request.getParameter("type").equals("Employee")) {
  Employee employee = daoPerson.getEmployee(Integer.valueOf(request.getParameter("ID")));
  modifyPerson(employee, request);
  employee.setSalary(request.getParameter("salary"));
  daoPerson.save(employee );
}
else {
  Person person = daoPerson.getPerson(Integer.valueOf(request.getParameter("ID")));
  modifyPerson(employee, request);
  daoPerson.save(person);
}

И, наконец, загрузка (в дао):

public Contact getPerson(int ID){
  Session session = HibernateSessionFactory.getSession();
  Person p = (Person) session.load(Person.class, new Integer(ID));
  return p; 
}

public Contact getEmployee(int ID){
  Session session = HibernateSessionFactory.getSession();
  Employee = (Employee) session.load(Employee.class, new Integer(ID));
  return p; 
}

При этом я получаю ClassCastException при попытке загрузить Person с помощью getEmployee.

Отображение XML Hibernate:

<class name="domain.Person" table="PERSON" discriminator-value="P">
        <id name="id" type="int">
            <column name="ID" />
            <generator class="native" />
        </id>

        <discriminator column="type" type="character"/>


        <property name="firstName" type="java.lang.String">
            <column name="FIRSTNAME" />
        </property>
        <property name="lastName" type="java.lang.String">
            <column name="LASTNAME" />
        </property>

  <subclass name="domain.Employee" discriminator-value="E">
    <property name="salary" column="SALARY" type="java.lang.String" />
  </subclass>
</class>

Это достаточно ясно? : - /

Ответы [ 2 ]

4 голосов
/ 17 января 2011

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

Когда я вас правильно понимаю - вам нужно преобразовать Человека в Сотрудника и обратно. Они использовали столбец дискриминатора, назовем его «диск» и предположим, что вы используете дискриминатор String с двумя значениями PERSON и EMPLOYEE. Затем вам нужен дополнительный столбец, который сопоставляет столбец дискриминатора с вашим классом Person. Давайте назовем это «hackType».

@Column(columnName=”disc”)
private String hackType;

Теперь у вас есть связанный hackType и тип объекта. Во-первых, вы должны убедиться, что hackType является ЧЕЛОВЕКОМ для всех сотрудников и РАБОТНИКОМ для всех сотрудников. - Но если вы хотите «передать» Person сотруднику, вам просто нужно загрузить Person (по идентификатору), установить для его поля hackType значение EMPLOYEE, сохранить его, очистить кэш и перезагрузить его (по идентификатору) как Сотрудник.

Но это действительно плохой взлом, я видел его для nHibernate, но я предполагаю, что он может работать и для (Java) Hibernate. - В любом случае Я настоятельно рекомендую не делать этого таким образом, , но интересно знать этот взлом.

По крайней мере, я считаю, что проблема в том, что модель вашего домена неверна: Сотрудник не должен быть подклассом Person. Потому что это будет означать, что Сотрудник всегда будет Сотрудником, а Персоном (если оно создано как личность) никогда не станет сотрудником. Я настоятельно рекомендую строить отношения 1: 1 между сотрудником и сотрудником. Где Person является основным объектом, а Employee является необязательным расширением для Person. (В этом случае вам нужно переименовать Employee в нечто вроде EmploymentFacts, чтобы было ясно, что это только часть Employee).

0 голосов
/ 17 января 2011

Не думаю, что есть хороший выход.Вы можете запустить запрос на обновление этого человека, чтобы изменить его тип на «E» и изменить зарплату, затем вы можете получить его, используя getEmployee(), если вам все еще это нужно.

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