hibernate和inheritance(TABLE_PER_CLASS)

我使用Hibernate来持久化inheritance的对象,但是当我尝试在数据库中持久保存对象时,我得到了这条消息:

org.springframework.dao.InvalidDataAccessResourceUsageException: Could not execute JDBC batch update; SQL [update Widget set CONTAINER_ID=? where WIDGET_ID=?]; nested exception is org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update (...) Caused by: java.sql.BatchUpdateException: Table 'schema.widget' doesn't exist 

这是我用来生成表的类:

 @Entity @Table(name="CONTAINER") public class Container { (...) private Set widgets; @OneToMany(targetEntity = Widget.class) @JoinColumn(name="CONTAINER_ID", nullable=true) public Set getWidgets() { return widgets; } public void setWidgets(Set widgets) { this.widgets = widgets; } } @Entity @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public abstract class Widget { private long id; private int position; @Id @GeneratedValue(strategy = GenerationType.TABLE) @Column(name="WIDGET_ID") public long getId() { return id; } public void setId(long id) { this.id = id; } @Column(name="POSITION") public int getPosition() { return position; } public void setPosition(int position) { this.position = position; } } @Entity @Table(name="TEXT_WIDGET") public class TextWidget extends Widget { (...) } @Entity @Table(name="IMAGE_WIDGET") public class ImageWidget extends Widget { (...) } 

所以这意味着Hibernate正在寻找表’widget’,但它没有被创建,因为我选择了InheritanceType.TABLE_PER_CLASS选项,因此只有具体的类有一个表。 在数据库中,我可以看到container,text_widget和image_widget表。

然后当我尝试执行此代码并保存容器时,我得到了上述错误:

 Set widgets = new HashSet(); widgets.add(textw1); // instance of TextWidget widgets.add(imgw1); // instance of ImageWidget Container container1 = new Container(); container1.setWidgets(widgets); 

谢谢你的帮助!

您的关联必须是双向的,如Hibernate文档中所述。

2.2.4.1。 每class表

这个策略有许多缺点(特别是多态查询和关联),在JPA规范,Hibernate参考文档,Hibernate in Action以及许多其他地方都有解释。 Hibernate解决了大多数使用SQL UNION查询实现此策略的问题。 它通常用于inheritance层次结构的顶级:

 @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class Flight implements Serializable { ... } 

该策略支持一对多关联, 前提是它们是双向的 。 此策略不支持IDENTITY生成器策略:必须在多个表之间共享id。 因此,在使用此策略时,不应使用AUTO或IDENTITY。

这样,Hibernate就能够在每个具体的widget表中创建适当的外键列。 这是一个实际有效的映射。 对于Container

 @Entity public class Container { @Id @GeneratedValue private long id; @OneToMany(targetEntity = Widget.class, mappedBy = "container", cascade = CascadeType.ALL) private Set widgets = new HashSet(); public long getId() { return id; } public void setId(long id) { this.id = id; } public Set getWidgets() { return widgets; } public void setWidgets(Set widgets) { this.widgets = widgets; } public void addToWidgets(Widget widget) { this.getWidgets().add(widget); widget.setContainer(this); } public void removeFromWidgets(Widget widget) { this.getWidgets().remove(widget); widget.setContainer(null); } } 

而抽象的Widget类:

 @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class Widget { @Id @GeneratedValue(strategy = GenerationType.TABLE) private long id; private int position; @ManyToOne private Container container; public long getId() { return id; } public void setId(long id) { this.id = id; } public int getPosition() { return position; } public void setPosition(int position) { this.position = position; } public Container getContainer() { return container; } public void setContainer(Container container) { this.container = container; } } 

以下测试方法(在事务中运行)只是传递:

 @Test public void testInsertContainer() { TextWidget textw1 = new TextWidget(); ImageWidget imgw1 = new ImageWidget(); Container container1 = new Container(); container1.addToWidgets(textw1); // instance of TextWidget container1.addToWidgets(imgw1); // instance of ImageWidget session.persist(container1); session.flush(); assertNotNull(textw1.getId()); assertNotNull(imgw1.getId()); assertNotNull(container1.getId()); } 

并生成以下SQL:

 21:59:57.964 [main] DEBUG org.hibernate.SQL  - 从hibernate_unique_key中选择next_hi只读rs
 21:59:57.978 [main] DEBUG org.hibernate.SQL  - 更新hibernate_unique_key设置next_hi =?  next_hi =?
 21:59:58.063 [main] DEBUG org.hibernate.SQL  -  null
 21:59:58.125 [main] DEBUG org.hibernate.SQL  - 插入Container(id)值(?)
 Hibernate:插入到Container(id)值(?)
 21:59:58.140 [main] TRACE org.hibernate.type.LongType  - 将'98304'绑定到参数:1
 21:59:58.145 [main] DEBUG org.hibernate.SQL  - 插入ImageWidget(container_id,position,id)值(?,?,?)
 Hibernate:插入ImageWidget(container_id,position,id)值(?,?,?)
 21:59:58.164 [main] TRACE org.hibernate.type.LongType  - 将'98304'绑定到参数:1
 21:59:58.165 [main] TRACE org.hibernate.type.IntegerType  - 将'0'绑定到参数:2
 21:59:58.166 [main] TRACE org.hibernate.type.LongType  - 将'32768'绑定到参数:3
 21:59:58.172 [main] DEBUG org.hibernate.SQL  - 插入TextWidget(container_id,position,id)值(?,?,?)
 Hibernate:插入TextWidget(container_id,position,id)值(?,?,?)
 21:59:58.187 [main] TRACE org.hibernate.type.LongType  - 将'98304'绑定到参数:1
 21:59:58.188 [main] TRACE org.hibernate.type.IntegerType  - 将'0'绑定到参数:2
 21:59:58.189 [main] TRACE org.hibernate.type.LongType  - 将'32769'绑定到参数:3

但请记住, 每个类策略的 对多态关系提供的支持很少 ,如果你有许多Widget子项,可能根本不适合(这将导致巨大的SQL UNION)。

相关问题

  • JPA多态oneToMany