aroth
aroth

Reputation: 54806

JPA/Hibernate - InheritanceType.JOINED behaves like InheritanceType.TABLE_PER_CLASS

I'm trying to implement a very simple inheritance model in Hibernate. Basically I have a single superclass which can be called A, and several subclasses all of which inherit from A. Since the behavior I'm seeing is the same for all of them, they can just be referred to as B.

What I'm trying to arrive at is what's described here in section 6.2. Basically, there should be a table for A that contains its fields, and a table for B that contains only the fields that are distinct to the subclass, plus a join column back to the table for A. I am using Hibernate's automatic schema generation (enabled for the development persistence-unit only).

What I see when I look at the schema, however, is a table for A the contains its fields (correct), and a table for B which contains all the fields in A (incorrect), plus the fields added in B. My classes are annotated as follows:

@Entity
@Table(name="A")
@Inheritance(strategy = InheritanceType.JOINED)
public class A implements Serializable {
    protected long id;
    protected Date createDate;
    protected String title;
    protected boolean hidden;

    public A() {
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long getId() {
        return id;
    }

    @Column(nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    public Date getCreateDate() {
        return createDate;
    }

    @Column(nullable = false)
    public boolean isHidden() {
        return hidden;
    }

    @Column(nullable = false)
    public String getTitle() {
        return title;
    }

    //also setters...   
}

@Entity
@Table(name="B")
@PrimaryKeyJoinColumn(name="aId", referencedColumnName="id")
public class B extends A {
    private String extraField;

    public B() {
        super();
    }

    @Column
    public String getExtraField() {
        return extraField;
    }

    //also setter...
}

Any ideas what I've done wrong? Specifically, what I want to see when I look at the generated DB schema is something like:

Table A:  {id, createDate, title, hidden}
Table B:  {aId, extraField}

...and instead what I get is:

Table A:  {id, createDate, title, hidden}
Table B:  {id, createDate, title, hidden, extraField}

Is this just not possible using Hibernate's automatic schema generation, or have I screwed up the annotations somewhere?

Upvotes: 4

Views: 7926

Answers (1)

Ken Chan
Ken Chan

Reputation: 90447

Your annotation is correct , it should produce the table schema that you want .

But now you get an undesired schema , which is exactly the schema produced using the Table per concrete class strategy (i.e @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)). So , I think one of the possible reason is that the hibernate.hbm2ddl.auto property in your configuration uses the default value , which is update .

The behavior of the update value is :

  • Hibernate will try to create an update script to update the database schema to the current mapping when the SessionFactory is created.

  • If an update statement cannot be performed , it will be skipped (For example adding a not null column to a table with existing data)

  • Hibernate will not delete any data during the update .(For example , if a column 's name is changed , it just add an new column with the new name , but still keep the column with the original name)

So , I think you must use @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) to generate the schema before , which produced the following schema . Table A and Table B do not have any foreign key associations to each other.

Table A:  {id, createDate, title, hidden}
Table B:  {id, createDate, title, hidden, extraField}

After that , you changed to use @Inheritance(strategy = InheritanceType.JOINED) . During the update schema process , hibernate just updated your scheme by adding a foreign key assocation between the TableA.id and TableB.id . It kept all other columns in Table B . That 's why you get the current schema even though your annotation is correct .

The desired table schema should be generated after you drop Table A and Table B from the DB before starting the hibernate programe . Alternatively , you can set the hibernate.hbm2ddl.auto to create , then hibernate will delete all tables before generating the table schema .

Upvotes: 4

Related Questions