JPA向下转换以访问子类方法

时间:2015-10-05 19:36:37

标签: java java-ee jpa persistence downcast

数据库表:

Employee Table
ID, Type, Salary, Rate

类型可以是全职或承包商。而全职工资的属性,承包商有费率的属性。 (我知道它没有正常化。但它就是它。如果你能教育我为什么这是一个糟糕的设计,那就感激不尽了)

JPA课程:(Oracle JPA)

@Entity
@Table(name="Employee")
public abstract class Employee{...}



@Entity
public class FullTimeEmployee extends Employee{...}



public class EmployeeService{
...
Employee joe = entityManager.find(Employee.class, id);
((FullTimeEmployee) joe).getSalary(); //Can I do this? 
//Or I have to use Employee joe = entityManager.find(FullTimeEmployee.class, id);
...
}

我可以通过这种方式转发实体类吗?谢谢!

编辑:

我的其他问题是这个。两种类型的员工都存储在同一个表中。那么entityManager.find(Employee.class,id)怎么知道哪个id是全时的呢?

那么,如果我这样做会有所作为吗

entityManager.persist((Employee)fullTimeEmp);

而不是

entityManager.persist(fullTimeEmp);

2 个答案:

答案 0 :(得分:1)

  

我可以用这种方式转发实体类吗?

你可以,它会起作用,但并不总是如此。所以我不会这样做。例如,如果您与员工有一个懒惰的toOne关联,或者您碰巧使用了em.getReference()来加载"在之前的同一会话中,您将获得ClassCastException,因为Hibernate将向Employee返回一个代理,既不是FullTimeEmployee也不是Contractor。

如果你避免使用instanceof并进行强制转换,并且使用多态性,那么你是安全的。例如,您可以在基类中定义抽象getSalary()方法,并在子类中提供不同的实现。或者你可以使用访客模式。

  

两种类型的员工都存储在同一个表中。那么如何实现entityManager.find(Employee.class,id)

它知道,因为你必须有一个鉴别器列,包含实体的类型。从数据库加载行时,Hibernate从该列读取类型并实例化相应的子类。

  

那么,如果我这样做会有所作为吗

entityManager.persist((Employee)fullTimeEmp);

不,一点也不。 fullTimeEmp的实际具体类型是FullTimeEmployee,无论您是否将其转换为Employee,以及Hibernate用于了解必须如何保存员工的内容(在这种情况下,它必须存储在哪个值中)鉴别器栏目。)

答案 1 :(得分:0)

由于您没有显式设置继承映射的策略,因此默认值为InheritanceType.SINGLE_TABLE。这意味着,所有持久化实体(无论持久化具体的子类类型)都将存储在单个表中。如果使用单个表,您很可能会有一个鉴别器列,它将区分应该是哪个子类类型的特定行。 这是一个很好的example

关于如何查询特定子类型的问题,您可以使用JP QL关键字TYPE。

示例:

SELECT e FROM Employee e WHERE TYPE(e) = FullTimeEmployee

此查询的结果将是所有FullTimeEmployee对象。

此外,如果您正在寻找给定ID的特定FullTimeEmployee对象。以下代码也是可能的:

em.find(FullTimeEmployee.class, id);