Hibernate:将基类的实例更改为子类

时间:2011-09-17 19:00:59

标签: java hibernate jpa

我想将一个具体的超类更改为其子类之一。我在下面列举了一个例子:

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

我正在使用的三个班级是员工,经理和历史。所有经理都是员工,但并非所有员工都是经理。所有员工(和经理)都有历史记录。员工可能会晋升为管理层。发生这种情况时,应通过保持员工ID相同来保留员工的历史记录。这样可以轻松找到经理人的就业历史。

实施促销操作因数据库的约束而变得复杂:数据库不允许删除旧的Employee并创建具有相同ID的新Manager而不通过级联操作删除所有History对象 - 人力资源部门不会允许,否则我的工作会很容易!

是否可以附加管理器(新管理员)行添加到现有员工而无需借助自定义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中是否可行?

在这一点上任何想法都会有所帮助,因为我很难过!

  • Aaron

2 个答案:

答案 0 :(得分:6)

正如你无疑开始看到的那样,你在风中划风。不幸的是,看起来你有using inheritance to represent role的典型例子。 Hibernate - 一个 Object - 关系映射器 - 和Java - 面向 Object 的语言 - 都会在这个问题上打击你,因为你的对象模型是错误的。我想说你最好的办法是通过重构和数据迁移来解决它。最终结果应该是每个人都是员工,而一些员工与一个或多个部门或其他员工之间存在某种“管理”关系。

答案 1 :(得分:1)

我遇到了类似的情况,我不相信有缺陷的数据模型是错误的,因为数据模型很好地匹配了现实世界的模型。

您可以手动插入子类记录以获得所需的结果。有时候绕过Hibernate来完成某些事情是必不可少的,所以这就是我在这种情况下所做的解决方法:

sessionFactory.getCurrentSession().createSQLQuery(
            "insert into manager (employee_id, rank) " +
            "values (:employeeId, :rank) ")
            .setParameter("employeeId", employeeId)
            .setParameter("rank", rank)
            .executeUpdate();