6

順序付けされた子を使用して、双方向の親子設計をモデル化しようとしています。

親から子 (例: 3 つの子のうちの子 #2) を削除すると、「削除」(ターゲット) の前に「更新」(兄弟) が実行されるため、休止状態で生成された SQL で一意制約違反が発生しました。

私が使用している RDBMS (H2) は、遅延制約をサポートしていません。次のオプション以外にどのようなオプションがありますか?

  • スキーマから一意の制約を削除します
  • 休止状態に依存するのではなく、自分でソートを明示的に管理します

'update' の前に 'delete' を指定して休止状態で SQL を生成する方法はありますか?


フォーラムで見つかったいくつかの古い議論:

コレクション内での DELETE と INSERT - 実行された SQL の順序


DB スキーマ:

CREATE TABLE IF NOT EXISTS  Sequences (
ID                      BIGINT NOT NULL AUTO_INCREMENT,
Name                    LONGVARCHAR,
Type                    LONGVARCHAR,
Sequence                LONGVARCHAR,

ParentId                BIGINT DEFAULT NULL,
Index                   INT,

CONSTRAINT pk_SequenceId    PRIMARY KEY     (ID),
CONSTRAINT uc_Sequences     UNIQUE          (ParentId, Index),
CONSTRAINT fk_Sequences
    FOREIGN KEY (ParentId) 
    REFERENCES Sequences(ID) 
        ON UPDATE CASCADE
        ON DELETE CASCADE
);

クラス:

public class Sequence {
    protected Long ID;
    protected String name;
    protected String type;
    protected String sequence;
    protected Sequence  parentSequence;
    protected List<Sequence> childSequences = new ArrayList<Sequence>();
}

HBM マッピング:

<hibernate-mapping>
<class name="Sequence" table="Sequences">
    <id name="ID" column="ID" type="long">
        <generator class="native"/>
    </id>

    <property name="name" type="string" column="Name"/>
    <property name="type" type="string" column="Type"/>
    <property name="sequence" type="string" column="Sequence"/>

    <many-to-one name="parentSequence" column="parentId" cascade="save-update" insert="false" update="false" class="Sequence" />

    <list name="childSequences" inverse="false" lazy="true" cascade="all-delete-orphan">
        <key column="parentId" not-null="true"/>
        <list-index column="Index" base="0"/>
        <one-to-many class="Sequence"/>
    </list>
</class>

4

1 に答える 1

4

Hibernate は HQL (または SQL) ステートメントを直接実行しませんがcommit()flush()最も効果的な方法で実行することを目標に、SQL ステートメントを並べ替えます。ただし、Hibernate からの再注文が間違っている可能性があり、たとえば、あなたの場合のように制約違反が発生します。

解決策は、中間体を導入することflush()です。flush()並べ替えを強制し、SQL ステートメントを送信しますが、コミットはしません。

あなたの場合、コードを(スケッチとして)次のように変更できます。

transaction = session.beginTransaction();
session.delete(obj);
session.flush();     /* newly introduced */
session.update(...);
transaction.commit();

問題がカスケード削除またはユーザーの制御なしに Hibernate によって実行される削除にある場合は、削除および更新プロセスを制御し、Hibernate の自動化に頼るのではなく、コードで操作を明示的に実行する必要があります。

于 2013-12-05T09:57:12.163 に答える