【问题标题】:Hibernate, Oracle, Join Tables and Key IssuesHibernate、Oracle、连接表和关键问题
【发布时间】:2011-06-17 01:12:40
【问题描述】:

我有 3 个表,ParentChildParentChild 将前两个表连接在一起。执行插入 (Parent.getChilds().add(new Child());) 时出现错误,因为显然尚未创建主键并且违反了约束:

java.sql.BatchUpdateException: ORA-02291: integrity constraint (TU.SYS_C0072908) violated - parent key not found

如果我让我的测试用例回滚,这可以正常工作,我没有违反约束,并且我的所有断言都通过了。如果我将测试用例设置为不回滚,则会出现上述错误。此外,如果 Parent 和 Child 是在当前事务之外创建的,那么一切都很顺利。即:

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 可以有多个ChildChild 只能有一个Parent。 (有人指出,不应该有连接表,而是应该是CHILD 表中的PARENTID 列,但这个设计决定不是我的决定。)

表格也很简单:

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)
);

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

我的设置有什么问题?

【问题讨论】:

    标签: java oracle hibernate


    【解决方案1】:

    “一个父级可以有多个子级,一个子级只能有一个父级。”

    那么你不应该有一个父子表,因为只需要一个连接表来解决多对多关系。

    子表应该只包含一个 PARENTID 列和父表的外键。

    【讨论】:

    • 虽然我同意你的观点,但数据库设计不在我的掌控之中。根据hibernate docs,这应该可以工作。
    【解决方案2】:

    问题在于应用序列 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>
    

    或者删除触发器和序列,让 hibernate 分配 id:

    <id name="childId">
        <generator class="native"/>
    </id>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-09
      • 1970-01-01
      • 2017-02-21
      • 2016-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多