对象模型是:
我已经通过让Part继承自Component,然后让Part有一个由它组成的Component对象的集合来建模。
当我尝试创建Part对象时,我遇到了完整性约束违规:
14:29:24,121 WARN JDBCExceptionReporter:100 - SQL Error: -177, SQLState: 23503
14:29:24,126 ERROR JDBCExceptionReporter:101 - integrity constraint violation: foreign key no parent; FK24013CDD89C7219B table: COMPONENT
查看hbm2ddl在下面生成的模式,看起来它正在创造一个不可能的情况。
继承FK
Part表通过FK获取PartID-> ComponentID的Component表,因为每个子类的表是预期的。
alter table Part add constraint FK25D813296E407B foreign key (PartID) references Component;
收藏品FK
它还通过FK生成从Component表到Part表的关系,ComponentID用于表示集合。然而,它是如何做到这一点有点未被发现。
alter table Component add constraint FK24013CDD89C7219B foreign key (ComponentID) references Part;
我原本期望它生成以下内容来代表集合:
alter table Component add constraint FK24013CDD89C7219B foreign key (PartID) references Part;
或者更一般地说
alter table <Name of class in the collection> add constraint FK123 foreign key (id of the class object which owns the collection) references (Name of the class that holds the collection)
我可以看到它实际上是如何选择ComponentID的,因为继承而将PartID FK加到ComponentID。但是,结果,我认为这已经创造了一种不可能的情况,其中Component表现在对自身有一个FK要求,这是永远无法满足的。
如何在同一继承树的派生类型中映射基类型对象的集合?
Java POJOs
package manufacturing;
public class Component {
private long _id;
private String _name;
private float _price;
// Hibernate requires all persistent classes to have a default constructor, even if it is private.
@SuppressWarnings("unused")
protected Component() {
this(-1L, "", 0.0f);
}
public Component(String name) {
this(-1L, name, 0.0f);
}
public Component(long id, String name, float price) {
setID(id);
setName(name);
setPrice(price);
}
public long getID() {
return _id;
}
// Required method for Hibernate
protected void setID(long id) {
_id = id;
}
public String getName() {
return _name;
}
public void setName(String name) {
_name = name;
}
public float getPrice() {
return _price;
}
public void setPrice(float price) {
_price = price;
}
}
package manufacturing;
import java.util.Collection;
import java.util.HashSet;
public class Part extends Component {
private Collection<Component> _subcomponents;
// Hibernate requires all persistent classes to have a default constructor, even if it is private.
@SuppressWarnings("unused")
private Part() {
this(-1L, "", 0.0f, new HashSet<Component>());
}
public Part(String name) {
this(-1L, name, 0.0f, new HashSet<Component>());
}
public Part(long id, String name, float price, Collection<Component> subcomponents) {
super(id, name, price);
setSubcomponents(subcomponents);
}
public Collection<Component> getSubcomponents() {
return _subcomponents;
}
public void setSubcomponents(Collection<Component> subcomponents) {
_subcomponents = subcomponents;
}
}
Hibernate Mapping
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="manufacturing">
<class name="Component" table="Component">
<id name="ID" column="ComponentID">
<generator class="native" />
</id>
<property name="name" column="Name" />
<property name="price" column="Price" />
<joined-subclass name="Part" table="Part">
<key column="PartID" />
<!-- A part has has [0..n] subcomponents -->
<set name="Subcomponents" lazy="true" cascade="all" inverse="true">
<key column="ComponentID" />
<one-to-many class="Component" />
</set>
</joined-subclass>
</class>
</hibernate-mapping>
HBM2DDL架构
create table Component (ComponentID bigint generated by default as identity (start with 1), Name varchar(255), Price float, primary key (ComponentID));
create table Part (PartID bigint not null, primary key (PartID));
alter table Component add constraint FK24013CDD89C7219B foreign key (ComponentID) references Part;
alter table Part add constraint FK25D813296E407B foreign key (PartID) references Component;
相关堆栈跟踪
14:28:15,001 DEBUG SessionImpl:257 - opened session at timestamp: 12798232950
14:28:47,299 DEBUG JDBCTransaction:82 - begin
14:28:47,313 DEBUG ConnectionManager:444 - opening JDBC connection
14:28:47,333 DEBUG JDBCTransaction:87 - current autocommit status: false
14:29:23,929 DEBUG AbstractSaveEventListener:320 - executing identity-insert immediately
14:29:23,941 DEBUG AbstractBatcher:410 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
14:29:23,948 DEBUG SQL:111 - insert into Component (ComponentID, Name, Price) values (null, ?, ?)
Hibernate: insert into Component (ComponentID, Name, Price) values (null, ?, ?)
14:29:23,966 DEBUG AbstractBatcher:418 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
14:29:23,991 DEBUG JDBCExceptionReporter:92 - could not insert: [manufacturing.Part] [insert into Component (ComponentID, Name, Price) values (null, ?, ?)]
java.sql.SQLException: integrity constraint violation: foreign key no parent; FK24013CDD89C7219B table: COMPONENT
at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2836)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
at DAO.GenericHibernateDAO.create(GenericHibernateDAO.java:91)
at DAO.PartDAOHibernateTest.testCreatePartWithNoSubcomponents(PartDAOHibernateTest.java:69)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
14:29:24,121 WARN JDBCExceptionReporter:100 - SQL Error: -177, SQLState: 23503
14:29:24,126 ERROR JDBCExceptionReporter:101 - integrity constraint violation: foreign key no parent; FK24013CDD89C7219B table: COMPONENT
答案 0 :(得分:1)