Search code examples
javahibernatejpawildflyjpa-2.1

Hibernate JPA creates a table per class with InheritanceType.JOINED


I have the following classes:

AbstractEntity, which is the super class to all my entities and stores common fields used by all entities, such as the id:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
...
}

AbstractUser, which is the super class to all user entities (admin, standard, etc.) and stores fields common to all user accounts, such as login name and password, etc:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class AbstractUser extends AbstractEntity implements Serializable

Example of a non-abstract user class, AdminUser:

@Entity
public class AdminUser extends AbstractUser implements Serializable {

What I would like to have is that I have ONE table for the AbstractUser class, which contains only the columns in the AbstractUser class and then for each subclass ONE table that contains all class specific values. I thought the @Inheritance(strategy = InheritanceType.JOINED) annotation in AbstractUser should do that. However, Hibernate produces a schema for me with a table for each class (AbstractUser and all classes that extend it) and the tables for the non-abstract classes contain all the columns of the abstract class.

When I persist an object of one of the classes that extend AbstractUser, all values are written to the more specific table, i.e. the AbstractUser table remains empty.

To clarify:
Say I have an AbstractUser class and AdminUser and StandardUser classes which extend AbstractUser. And then I persist one AdminUser object with id 1 and name 'A' and one StandardUser with id 2, name 'B' and account number '001', I would end up with this:

AbstractUser:

| ID | NAME |
empty table

AdminUser:

| ID | NAME |
|  1 |   A  |

StandardUser:

| ID | NAME | AccountNum |
|  2 |   B  |     001    |

What I would like to get is:

AbstractUser:

| ID | NAME |
|  1 |   A  |
|  2 |   B  |

AdminUser:

| ForeignKey |
|      1     |

StandardUser:

| ForeignKey | AccountNum |
|      2     |     001    |

What is wrong with the annotation I am using? How can I achieve this?

Just in case, my persistence.xml:

<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="cfadbPU" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/cfadbDS</jta-data-source>
<properties>
  <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
        <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/cfadb"/>
        <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
        <property name="hibernate.connection.username" value="*****"/>
        <property name="hibernate.connection.password" value="*****"/>
        <property name="hibernate.default_schema" value="public"/>
        <property name="hibernate.connection.autocommit" value="false"/>
        <property name="hibernate.enable_lazy_load_no_trans" value="true"/>
        <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
  </properties>
 </persistence-unit>
</persistence>

UPDATE:

I had a look through the server log and saw these messages:

 WARN  [org.hibernate.cfg.AnnotationBinder] (ServerService Thread Pool -- 187) HHH000138: Mixing inheritance strategy in a entity hierarchy is not allowed, ignoring sub strategy in: entities.users.AbstractUser
 WARN  [org.hibernate.cfg.AnnotationBinder] (ServerService Thread Pool -- 187) HHH000137: Root entity should not hold an PrimaryKeyJoinColum(s), will be ignored
 WARN  [org.hibernate.cfg.AnnotationBinder] (ServerService Thread Pool -- 187) HHH000137: Root entity should not hold an PrimaryKeyJoinColum(s), will be ignored

Is the error Mixing inheritance strategy there, because I first have TABLE_PER_CLASS for AbstractEntity and then JOINED for AbstractUser? If that is the reason for the error, why is it not allowed to mix inheritance types? I don;t see how that could cause any issues??


Solution

  • AbstractEntity should be a MappedSuperclass rather than an Enity.

    http://en.m.wikibooks.org/wiki/Java_Persistence/Inheritance#Mapped_Superclasses

    Mapped superclass inheritance allows inheritance to be used in the object model, when it does not exist in the data model.

    @MappedSuperclass
    public abstract class AbstractEntity implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected Long id;
    ...
    }