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

Java JPA向下转换以访问子类方法,java,jakarta-ee,jpa,persistence,downcast,Java,Jakarta Ee,Jpa,Persistence,Downcast,数据库表: Employee Table ID, Type, Salary, Rate 类型可以是全职或承包商。全职具有工资属性,承包商具有费率属性。 (我知道它不是标准化的。但它就是这样。如果你能告诉我为什么它是一个糟糕的设计,我将不胜感激) JPA类:(甲骨文JPA) 我可以用这种方式向下转换实体类吗?谢谢 编辑: 我的其他关切是这一点。这两种类型的员工都存储在同一个表中。那么,entityManager.find(Employee.class,id)怎么知道哪个id是全职的呢 那么,如果

数据库表:

Employee Table
ID, Type, Salary, Rate
类型可以是全职或承包商。全职具有工资属性,承包商具有费率属性。 (我知道它不是标准化的。但它就是这样。如果你能告诉我为什么它是一个糟糕的设计,我将不胜感激)

JPA类:(甲骨文JPA)

我可以用这种方式向下转换实体类吗?谢谢

编辑:

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

那么,如果我这样做会有什么不同吗

entityManager.persist((Employee)fullTimeEmp);
而不是

entityManager.persist(fullTimeEmp);
我可以用这种方式向下转换实体类吗

你可以,它也会起作用,但并不总是如此。所以我不会这么做。例如,如果您与某个员工有lazy toOne关联,或者您之前在同一个会话中使用em.getReference()来“加载”该员工,您将得到ClassCastException,因为Hibernate将向该员工返回一个代理,该员工既不是全职员工,也不是承包商

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

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

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

那么,如果我这样做会有什么不同吗

entityManager.persist((Employee)fullTimeEmp);

不,一点也不。实际的、具体的
fullTimeEmp
类型是FullTimeEmployee,无论您是否将其转换为Employee,这就是Hibernate用来了解必须如何保存员工(在本例中,它必须存储在鉴别器列中的值)。

因为您没有明确设置继承映射的策略,默认值为InheritanceType.SINGLE_表。这意味着,所有持久化的实体(不管持久化的是什么具体的子类类型)都将存储在一个表中。如果使用单个表,则很可能会有一个鉴别器列,用于区分特定行的子类类型。 这是一个好主意

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

例如:

SELECT e FROM Employee e WHERE TYPE(e) = FullTimeEmployee
此查询的结果将是所有FullTimeEmployee对象

此外,如果您正在查找给定ID的特定FullTimeEmployee对象,也可以使用以下代码:

em.find(FullTimeEmployee.class, id);

是的,如果你知道他是全职员工。您收到的是一个Employee实例,其行为类似于任何java对象。如果它不是FullTimeEmployee或其子类之一,您将得到ClassCastException。如果要防止异常,您可能需要使用find(FullTimeEmployee.class,id),而不是处理如果没有具有指定id的FullTimeEmployee时可能发生的问题。@Chris谢谢!我的其他关切是这一点。这两种类型的员工都存储在同一个表中。那么为什么entityManager.find(Employee.class,id)知道哪个id是全职的呢?当然,我需要entityManager.persist(fullTimeEmp);如果我做了entityManager.persisit((雇员)全职EMP),会有什么不同吗
em.find(FullTimeEmployee.class, id);