使用InheritanceType.JOINED时如何避免空子表?

时间:2018-09-24 11:58:08

标签: java spring spring-boot jpa inheritance

我有一个JPA超类和几十个子类。这些子类大多数都不添加特定的属性。

在使用InheritanceType.JOINED时,JPA为每个子类假定一个子表,从而导致大量过时的数据库表,使数据库管理和查询更加困难。

我的超类当前看起来像这样:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type")
public abstract class Employee {
    @Id public int id;
    public String firstName;
    public String lastName;
    public Date birthday;
}

某些子类具有特定的字段:

@Entity
public class ProjectManager extends Employee {
    public String project;
}

但是大多数子类都是空的,

@Entity
public class Director extends Employee {
}

@Entity
public class FacilityManager extends Employee {
}

这些数据库表很有意义:

employee(id, first_name, last_name, birthday)
project_manager(id, project)

如何避免使用这些过时的表?

director(id)
facility_manager(id)

如果我不创建它们,JPA验证将失败:

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    ...
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [director]
    at org.hibernate.tool.schema.internal.SchemaValidatorImpl.validateTable(SchemaValidatorImpl.java:67) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    ...

2 个答案:

答案 0 :(得分:2)

有一个解决方案,但仅在使用EclipseLink时才适用。 Hibernate不支持此功能:

  

混合继承

     

JPA要求仅在根目录中定义继承策略   类。如果要混合使用SINGLE_TABLE和JOINED   可以通过在根类中使用JOINED继承来实现,   并指定子类上的Table与父类相同。

示例:将JOINED与混合继承一起使用

@Entity
// This subclass does not define its own table, but shares its parent's ACCOUNT table.
@Table(name="ACCOUNT")
@DiscriminatorValue("3")
public class StandardAccount extends Account {
   ...
}

来源:https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Entities/Inheritance#Mixed_Inheritance

答案 1 :(得分:0)

  1. 拥有没有任何字段的子类无疑是一种有效的构造,但是在我三十年的职业生涯中,我从未遇到过这种构造的需要,因此我愿意打赌,您的设计不是很经过深思熟虑,或者您只是还没有发现以后需要使用的字段。

  2. 即使我们将空子类视为拥有的合法构造,您对省略相应表的额外要求也不一定是要支持的合理功能。省略这些表可能会在hibernate的源代码中不时需要一些额外的if语句,但是这种用法极为罕见,因此支持它很不值得。仅仅花一点点时间就不值得负担源代码,也不值得编写必要的测试来支持它。

  3. 即使Hibernate支持在空子类上删除子类表,这样做也可能导致某些功能丢失。例如,可能没有这些表,休眠状态就不可能回答诸如“找我所有董事”或“找我所有设施经理”之类的查询。再次,代替子类表,休眠仍可能通过查询基类表来回答此类查询,但这不是正常的操作模式(会更昂贵),因此需要在休眠状态下编码一种特殊情况,以支持这种极为罕见的请求。同样,这也不是合理的事情。

  4. 在问题中您提到“如果我不创建它们,...”-您确定正确使用了Hibernate吗?您不必创建它们,而是应该可以让冬眠为您做到这一点。通常,您不必管理数据库(因此所有这些空表都不会成为您的问题),因为使用休眠模式的全部要点是,这样我们就不必处​​理数据库了。当我使用休眠模式时,我很少看桌子,甚至常常不知道那里有什么桌子,休眠模式使我在大多数情况下都不必担心。建议每隔一段时间查看一下数据库的状态,以确保不会出现意外情况,但这与管理数据库并承受一些不必要的表之类的事情相去甚远。