【问题标题】:Hibernate: Change instance of base class to subclassHibernate:将基类的实例更改为子类
【发布时间】:2011-09-17 19:00:59
【问题描述】:

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

@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 相同来保留员工的历史记录。这样可以轻松找到经理的就业历史。

由于数据库的约束,实现提升操作变得复杂:数据库不允许删除旧员工并创建具有相同 ID 的新经理,而无需通过级联操作删除所有历史对象 - 人力资源部不会允许,否则我的工作会很轻松!

是否可以在不借助自定义 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 中可行吗?

此时任何想法都会有所帮助,因为我很难过!

  • 亚伦

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    毫无疑问,正如您开始看到的那样,您在这里逆风划船。不幸的是,您似乎有一个经典的using inheritance to represent role 示例。 Hibernate——一种Object——关系映射器——和Java——一种面向Object的语言——都会在这方面与你抗衡,因为你的对象模型是错误的.我想说你最好的选择是现在通过重构和数据迁移来修复它。最终的结果应该是每个人都是 Employee,而一些员工与一个或多个部门或其他员工有某种“管理”关系。

    【讨论】:

    • Hibernate 没有处理这种常见的 OO 故障的 in-Hibernate 方式吗?该问题也可以描述为对象身份问题:我希望能够告诉 Hibenate,仅针对一个事务,忘记尝试保留 .equals() 和 == 语义学家 - 让我让对象不相等, !=,然后也是 equal(),指示它为子类执行 INSERT。我知道它会使持久性 VM 状态有些不一致 - 该应用程序实际上是为此设计的(没有缓存等......)。还有其他想法吗?
    • @Aaron:你有映射的 Employee->History 关系吗?如果是这样,您应该能够创建一个 Manager 对象,将旧 Employee 的所有属性复制到新 Manager,然后在 Manager 的历史记录中设置 History 对象并将 Employee 的历史记录设置为 null,从而实质上转移了对从 Employee 实例到 Manager 实例的历史记录。
    • 谢谢!是的,这似乎就是我需要做的事情(或类似的事情:()。最初我认为低级休眠/jpa 方法之一有助于管理身份的变化——但它不起作用.
    【解决方案2】:

    我遇到了类似的情况,我不认为有缺陷的数据模型是罪魁祸首,因为数据模型与现实世界的模型非常匹配。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多