Hibernate: изменение экземпляра базового класса на подкласс - PullRequest
7 голосов
/ 17 сентября 2011

Я хотел бы изменить конкретный суперкласс на один из его подклассов. Я включил пример ниже:

@Entity
@Table(name = "employees")
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee {

    @Id
    @Column(name = "id")
    private String id;

    public Employee( String id ) {
        this.id = id;
    }
 ...
}

@Entity
@Table(name = "managers")
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id")
public class Manager extends Employee {

    public Manager( String id ) {
        super(id);
    }
 ...
}


@Entity
@Table(name = "history")
public class History {
 ...
/**
 * 
 */
@ManyToOne
@JoinColumn(name = "employee_id")
private Employee employee;
 ...
}

Три класса, с которыми я работаю - это Сотрудник, Менеджер и История. Все руководители являются сотрудниками, но не все сотрудники являются менеджерами. Все сотрудники (и менеджеры) имеют историю. Сотрудники могут быть повышены до менеджмента. Когда это происходит, историю сотрудника следует сохранять, сохраняя его идентификатор сотрудника. Это позволит легко найти историю менеджера по трудоустройству.

Реализация операции продвижения усложняется из-за ограничений, связанных с базой данных: база данных не позволит удалить старого сотрудника и создать нового менеджера с тем же идентификатором, не удаляя все объекты истории с помощью каскадной операции, чего не будет с персоналом разрешить, иначе моя работа была бы легкой!

Можно ли добавить или присоединить строку менеджера (новых менеджеров) к существующему сотруднику, не прибегая к пользовательской операции SQL?

Я безуспешно пробовал следующие решения:

public void promote( Employee employee ) {
    /* copy over the ID of the employee to the manager.  Will not work because employee with ID already exists */
    Manager manager = new Manager(employee.getId());
    this.entityManager.persist( manager );
}

... или ...

public void promote( Employee employee ) {
    /* detach the employee then merge.  Will not work: fails, again, with a NonUniqueObject Exception */
    this.entityManager.detach( employee );
    Manager manager = new Manager(employee.getId());
    this.entityManager.merge( manager );
}

Как я могу это сделать? Я даже на правильном пути с detach () и merge () ?

Возможно ли это в Hibernate / JPA?

Любые идеи будут полезны на этом этапе, так как я в тупике!

  • Аарон

Ответы [ 2 ]

6 голосов
/ 17 сентября 2011

Как вы, без сомнения, начинаете видеть, вы гребете здесь против ветра. К сожалению, похоже, у вас есть классический пример , использующий наследование для представления роли . И Hibernate - Object -Реляционный Mapper - и Java - Object -ориентированный язык - будут бороться с вами на этом, потому что ваша объектная модель неверна. Я бы сказал, что лучше всего исправить это сейчас с помощью рефакторинга и переноса данных. Конечный результат должен состоять в том, что каждый сотрудник является сотрудником, а некоторые сотрудники имеют какие-то «управляющие» отношения с одним или несколькими отделами или другими сотрудниками.

1 голос
/ 15 июня 2012

Я столкнулся с подобной ситуацией, и я не верю, что виновата ошибочная модель данных, поскольку модель данных вполне соответствует модели реального мира.

Вы можете вставить запись подкласса вручную для достижения желаемого результата.Иногда бывает необходимо обойти Hibernate, чтобы что-то сделать, поэтому вот что я сделал в этом случае в качестве обходного пути:

sessionFactory.getCurrentSession().createSQLQuery(
            "insert into manager (employee_id, rank) " +
            "values (:employeeId, :rank) ")
            .setParameter("employeeId", employeeId)
            .setParameter("rank", rank)
            .executeUpdate();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...