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
- 如何调试“找到同一个集合的两个表示”?
- Hibernate 3.6.10不会通过OneToMany JoinTable级联删除
- 创建名为’sessionFactory’的bean时出错:MalformedParameterizedTypeException
- hibernate查询语言还是使用标准?
- 使用Hibernate持久收集界面
- 避免同一缓存区域的多次重新填充(由于并发)
- Spring源码套件spring3 + Hibernate4 + maven 3 + MySQL 5
- 将Hibernate查询结果映射到自定义类?
- 没有节点的数据类型:org.hibernate.hql.internal.ast.tree.IdentNode HQL