我有3个表,Parent
,Child
和ParentChild
将前两个表连接在一起。在进行插入(Parent.getChilds().add(new Child());
)时,我收到错误,因为显然主键尚未创建,并且我遇到了约束违规:
java.sql.BatchUpdateException: ORA-02291: integrity constraint (TU.SYS_C0072908) violated - parent key not found
如果我让我的测试用例回滚,这样可以正常工作,我没有违反约束,并且我的所有断言都通过了。如果我将我的测试用例设置为不回滚,则会出现上述错误。此外,如果父母和子女是在当前交易之外创建的,那么一切都很有效。即:
Parent parent = parentDao.get(parentId);
Child child = childDao.get(childId);
parent.getChilds().add(child);
child.setParent(parent);
parentDao.save(parent);
映射看起来像这样:
父
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.whatev">
<class name="Parent">
<id name="parentId">
<generator class="native"/>
</id>
<set name="childs" table="ParentChild" cascade="all">
<key column="parentId"/>
<many-to-many class="Child" column="childId" unique="true"/>
</set>
</class>
</hibernate-mapping>
子
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.whatev">
<class name="Child">
<id name="childId">
<generator class="native"/>
</id>
<join table="ParentChild" inverse="true">
<key column="childId"/>
<many-to-one name="Parent" column="parentId" not-null="true"/>
</join>
</class>
</hibernate-mapping>
Parent
可以有多个Child
,而Child
只能有一个Parent
。 (有人指出,应该没有联接表,而是PARENTID
表中的CHILD
列,但这个设计决定不是我要做的。)
表格也很简单:
CREATE TABLE PARENT (
PARENTID NUMBER(38) NOT NULL,
PRIMARY KEY(PARENTID)
);
CREATE TABLE CHILD (
CHILDID NUMBER(38) NOT NULL,
PRIMARY KEY(CHILDID)
);
CREATE TABLE PARENTCHILD (
PARENTID NUMBER(38) NOT NULL,
CHILDID NUMBER(38) NOT NULL,
FOREIGN KEY(PARENTID) REFERENCES PARENT(PARENTID),
FOREIGN KEY(CHILDID) REFERENCES CHILD(CHILDID),
UNIQUE (PARENTID, CHILDID)
);
创建记录时,主键由序列通过触发器填充。
我的设置有什么问题?
答案 0 :(得分:2)
“父母可以有一个以上的孩子而一个孩子只能有一个父母。”
那么你不应该有一个parentchild表,因为只需要一个连接表来解决多对多的关系。
子表应该只包含一个PARENTID列,其中包含父表的外键。
答案 1 :(得分:1)
问题在于触发器应用序列nextval。
通过指定native
但不告诉hibernate关于序列,hibernate认为它必须提出id本身,因为Oracle没有任何内容创建唯一ID。 Child.childId
将具有序列中的nextval(因为触发器覆盖了hibernate提供的内容)并且ParentChild.childId
获取了hibernate分配的值,从而产生了约束问题。
要以跨数据库友好的方式处理此问题,请先删除触发器,保留序列并让Oracle处理ID:
<id name="childId">
<generator class="native">
<param name="sequence">CHILDID_SEQ</param>
</generator>
</id>
或者删除触发器和序列,让休眠分配id:
<id name="childId">
<generator class="native"/>
</id>