如何使用Hibernate将ORM转换为其子类?

时间:2011-01-17 09:57:24

标签: java hibernate orm inheritance

例如,我有两个类:Person和Employee(Employee是Person的子类)。 人:有一个姓氏和一个名字。 员工:还有薪水。

在客户端,我有一个HTML表单,我可以填写人员信息(如姓氏和名字)。我在“人员”和“员工”之间也有一个“切换”,如果交换机在员工上,我可以填写工资字段。

在服务器端,Servlet从客户端接收信息,并使用Hibernate框架在数据库中创建/更新数据。我正在使用的映射是针对个人和员工的单个表,带有鉴别器。

我不知道如何将Person转换为Employee,方法是修改typeDiscriminatorColumn用作public class Person { protected int id; protected String firstName; protected String lastName; // usual getters and setters }

我首先尝试:

  • 从数据库加载Person p
  • 创建一个空的Employee e对象
  • 将值从p复制到e
  • 设置工资值
  • 将e保存到数据库中

但我不能,因为我也复制了ID,所以Hibernate告诉我他们两个实例化的ORM具有相同的ID。

我不能直接将Person转换为Employee,因为Person是Employee的超类。

似乎有一种肮脏的方式:删除这个人,并创建一个具有相同信息的员工,但我真的不喜欢它..

所以我很感激任何帮助:)

一些准确性:

人员班:

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);
}

在servlet中:

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

最后,加载(在dao中):

<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>

有了这个,我在尝试使用getEmployee加载Person时遇到ClassCastException。

XML Hibernate映射:

{{1}}

足够清楚了吗? : - /

2 个答案:

答案 0 :(得分:4)

几年前,当我做了一次评论时,我发现了一个可以解决问题的糟糕的黑客攻击

当我理解你的时候 - 你需要将一个人转变为一个雇员然后回来。 他们使用了一个鉴别器列,我们称之为“disc”,并假设你使用一个带有两个值PERSON和EMPLOYEE的字符串鉴别器。然后你需要一个额外的列,将鉴别器列映射到你的Person类。我们称之为“hackType”。

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

现在你已经加入了hackType和Object的类型。首先,您需要确保所有员工的hackType为PERSON,所有员工为EMPLOYEE。 - 但是如果你想将一个Person“转移”给一个Employee,你只需要加载Person(按ID),将其字段hackType设置为EMPLOYEE,保存它,清除缓存,并将其重新加载(通过ID)作为雇员。

但这是一个非常糟糕的黑客,我已经看到它用于nHibernate,但我认为它也适用于(Java)Hibernate。 - 无论如何我强烈建议不要这样做,但知道这个黑客很有意思。

至少我认为问题在于您的域模型是错误的:员工不应该是Person的子类。因为这意味着Employee将始终是Employee和Person(如果它是作为一个人创建的)将永远不会成为一个员工。我强烈建议在Person和Employee之间建立1:1的关系。 Person是主要对象,Employee是Person的可选扩展。 (在这种情况下,您需要将Employee重命名为像EmploymentFacts这样的东西,以明确这只是一个人的员工部分。)

答案 1 :(得分:0)

我认为没有好的出路。您可以在此人上触发更新查询以将其类型修改为“E”并更改薪水,如果仍需要,则可以使用getEmployee()获取该更新。