JPA / Hibernate - InheritanceType.JOINED的行为类似于InheritanceType.TABLE_PER_CLASS(JPA/Hibernate - InheritanceType.JOINED behaves like InheritanceType.TABLE_PER_CLASS)

我正在尝试在Hibernate中实现一个非常简单的继承模型。 基本上我有一个可以称为A超类,以及几个继承自A子类。 由于我所看到的行为对于所有这些行为都是相同的,因此它们可以简称为B

我想要达到的是6.2节中描述的内容。 基本上,应该有一个包含其字段的A表和一个仅包含与子类不同的字段的B表,以及一个返回表的A的连接列。 我正在使用Hibernate的自动模式生成(仅用于开发持久性单元)。

然而,当我查看模式时,我看到的是A表包含其字段(正确), B表包含A中的所有字段(不正确),以及B添加的字段。 我的课程注释如下:

@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... }

我做错了什么想法? 具体来说,当我查看生成的数据库模式时,我想看到的是:

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

...而我得到的是:

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

这是不可能使用Hibernate的自动模式生成,还是我搞砸了某处的注释?

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?

最满意答案

您的注释是正确的,它应该生成您想要的表模式。

但是现在你得到了一个不受欢迎的模式,这正是使用Table per concrete class策略生成的模式(即@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) )。 所以,我认为可能的原因之一是配置中的hibernate.hbm2ddl.auto属性使用默认值,即update 。

update值的行为是:

在创建SessionFactory时,Hibernate将尝试创建更新脚本以将数据库模式更新为当前映射。

如果无法执行更新语句,则会跳过该语句(例如,将非空列添加到包含现有数据的表)

Hibernate在更新期间不会删除任何数据。(例如,如果更改了列的名称,它只会添加一个带有新名称的新列,但仍保留具有原始名称的列)

所以,我认为你必须使用@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)来生成模式,这会生成以下模式。 表A和表B彼此之间没有任何外键关联。

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

之后,您更改为使用@Inheritance(strategy = InheritanceType.JOINED) 。 在更新架构过程中,hibernate刚刚通过在TableA.id和TableB.id之间添加外键TableA.id更新您的方案。 它保留了表B中的所有其他列。 这就是为什么即使您的注释是正确的,您也可以获得当前架构。

在启动hibernate程序之前,从数据库中删除表A和表B后,应生成所需的表模式。 或者,您可以将hibernate.hbm2ddl.auto设置为create ,然后hibernate将在生成表模式之前删除所有表。

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 .

更多推荐