Hibernate,Oracle,连接表和关键问题

时间:2011-06-17 01:12:40

标签: java oracle hibernate

我有3个表,ParentChildParentChild将前两个表连接在一起。在进行插入(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)
);

创建记录时,主键由序列通过触发器填充。

我的设置有什么问题?

2 个答案:

答案 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>