Hibernate, Oracle, таблицы соединений и ключевые вопросы - PullRequest
1 голос
/ 17 июня 2011

У меня есть 3 таблицы, Parent, Child и ParentChild, которые соединяют первые две вместе. При выполнении вставки (Parent.getChilds().add(new Child());) я получаю ошибку, потому что, по-видимому, первичный ключ не был создан, и я получаю нарушение ограничения:

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

Если я разрешу откат моего тестового примера, это будет работать нормально, я не получу нарушение ограничения, и все мои утверждения пройдут. Если я установлю свой тестовый случай, чтобы не выполнять откат, я получаю вышеуказанную ошибку. Кроме того, если родитель и потомок были созданы вне текущей транзакции, тогда все работает безупречно. I.e.:

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>

A Parent может иметь более одного Child, а Child может иметь только один 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)
);

Первичные ключи заполняются последовательностями через триггер при создании записи.

Что не так с моей настройкой?

Ответы [ 2 ]

2 голосов
/ 17 июня 2011

"Родитель может иметь более одного ребенка, а ребенок может иметь только одного родителя."

Тогда у вас не должно быть таблицы родительских элементов, поскольку таблица объединения необходима только для разрешения многих ко многимотношения.

Дочерняя таблица должна просто содержать столбец PARENTID с внешним ключом к родительской таблице.

1 голос
/ 17 июня 2011

Проблема заключается в том, что триггер применяет последовательность nextval.

Указав native, но не сообщая hibernate о последовательности, hibernate думает, что должен придумать сам идентификатор, поскольку у Oracle нетвсе, чтобы изначально создавать уникальные идентификаторы.Child.childId будет иметь следующее значение из последовательности (из-за того, что триггер перезаписывает то, что предлагает hibernate), а ParentChild.childId получает значение, которое назначает hibernate, создавая проблему ограничения.

Для обработки этого в кросс-дружественный к базе данных способ: либо сбросьте триггер, сохраните последовательность и дайте Oracle обработать идентификаторы:

<id name="childId">
    <generator class="native">
        <param name="sequence">CHILDID_SEQ</param>
    </generator>
</id>

Или удалите триггер и последовательность и дайте hibernate назначить идентификаторы:

<id name="childId">
    <generator class="native"/>
</id>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...