2

Я пытаюсь смоделировать двунаправленный родительско-дочерний дизайн с упорядоченными детьми.Как изменить порядок выполнения sql в hibernate

При удалении дочернего элемента (например, ребенка № 2 из 3-х детей) из родителя, сгенерированный sql-модуль спящего режима привел к уникальному нарушению ограничения, поскольку перед «удалением» (мишенью) выполняется «обновление» (сиблинг).

RDBMS, который я использую (H2), не поддерживает отложенное ограничение. Каковы варианты, которые у меня есть, помимо следующего?

  • удалить ограничение уникальности из схемы
  • явно управлять сортировкой сам, а не зависеть от спячки

Есть ли способ, чтобы сделать спящий режим генерации SQL с «удалить» «обновления» предшествует?


Некоторые старые дискуссии нашли в форуме:

DELETE then INSERT in collection - Order of executed SQL


DB Schema:

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 Mapping:

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

ответ

0

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.

+1

спасибо за предложение. будет очень сложно вручную выполнить повторный заказ, поскольку может произойти несколько операций (чередование add/remove) (как работает бизнес-логика приложения), прежде чем объект будет возвращен модулю сохранения (например, при сохранении) :( – YeenFei

+0

Флеш также может быть неявным образом, когда вы вызываете конкретный запрос выбора и все еще ожидаете изменения, которые должны быть сброшены, Hibernate может просто решить, что они сами сбросят их. – Gimby

Смежные вопросы