Невозможно перейти в спящий режим, чтобы удалить дочерние экземпляры через каскад, которые были удалены из отношения один ко многим
Небольшая проблема здесь:
У меня есть два класса сущностей, скажем
class Parent {
Set<Child> children;
}
class Child {
SomethingElse reference;
}
Теперь отображение по существу:
<class name="Parent" lazy="false">
<set name="children" lazy="false" cascade="all-delete-orphan">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
</class>
(здесь я опустил отображения идентификаторов и поля, я использую обычные идентификаторы)
По сути, мне нужно поддерживать чистую базу данных, поскольку, когда я удаляю элементы из списка родителя, а затем фиксирую родителя, соответствующие удаленные записи дочерней базы данных должны быть удалены. Дочерние экземпляры ссылаются на другие сущности, которые мне нужно будет удалить позже, поэтому, если дочерний экземпляр остается в базе данных, я не могу удалить эти ссылочные объекты.
То, что я обнаружил до сих пор: любая из вещей, которые я попробую ниже, должна работать, если я хочу сохранить упаковку PersistentCollection в hibernate. Проблема заключается в том, что мои объекты базы данных проходят через несколько уровней каркасов, которые включают в себя инфраструктуру пользовательского интерфейса, которая использует абстракции свойств бина для вызова сеттеров, и сетевой уровень связи, который клонирует и сериализует объекты назад и вперед. Оба этих слоя внутренне заменяют экземпляры коллекции и, таким образом, удаляют эти оболочки PersistentCollection. Переписать их, чтобы не делать это, не вариант.
Тем не менее, я попробовал 8 вещей, которые не сработали:
1) настроить отношение как cascade="all", использовать session.update (parent).
2) настроить отношение как cascade="all-delete-orphan", использовать session.update (parent).
3) настроить отношение как cascade = "all" и использовать session.merge(parent)
Все это приводит к тому, что hibernate выполняет "UPDATE CHILD SET parent.id = null WHERE parent.id = ...". Это успешно удаляет дочерние элементы из родительского списка при перезагрузке родительского экземпляра, но дочерний экземпляр остается в базе данных и не позволяет мне удалить другие ссылочные объекты.
4-6) использование конфигурации 1-3 с дополнительным определением столбца родительского ключа как ненулевого
Это приводит к тому, что hibernate ничего не делает. В другом посте я прочитал, что если сделать ключевой столбец ненулевым, это приведет к удалению. Звучит возможно, так как обновление до нуля больше не вариант, но не работает. Если я удаляю детей из коллекции, фиксирую изменения и перезагружаю экземпляр из базы данных, дети появляются снова.
7 + 8) родительский ключ, равный нулю или ненулевому, не имеет значения, но настройте отношение как cascade=all-delete-orphans и используйте session.merge(parent)
Это приводит к тому, что hibernate генерирует исключение "Коллекция с cascade =" all-delete-orphan "больше не ссылалась на экземпляр объекта-владельца" из-за удаленной оболочки PersistentCollection.
Чтобы решить мою проблему, единственное, что мне нужно, это Hibernate, чтобы выполнить запрос из опций 1-3 как УДАЛИТЬ вместо ОБНОВЛЕНИЯ. Я надеюсь, что просто не могу найти возможность настроить сопоставление таким образом, чтобы удалить их без упаковщиков PersistentCollection, но сейчас мне кажется, что такой опции нет. Кто-нибудь знает, есть ли способ настроить это?
/ edit: Чтобы уточнить, пример того, что я хочу, чтобы произошло:
Parent parent = new Parent();
parent.setChildren(new HashSet<Child>(Arrays.asList(new Child()))));
session.insert(parent)
// this correctly results in (approximately):
// SQL> INSERT INTO PARENT ...
// SQL> INSERT INTO CHILD ...
parent.setChildren(new HashSet<Child>()); // using .clear() is not an option.
session.update(parent);
// this results in:
// SQL> UPDATE CHILD set parent_id = null WHERE parent_id = ${id.of.parent}
// but i need this to result in:
// SQL> DELETE FROM CHILD WHERE parent_id = ${id.of.parent}
2 ответа
Хорошо, я, видимо, исправил это сейчас. Проблема заключалась в том, что я назначал не пустой набор, а ноль. По-видимому, в случае session.merge (обновлено) hibernate внезапно различает пустые коллекции и нулевые коллекции. Использование cascade="all-delete-orphan" и.merge() с пустыми экземплярами коллекции, назначенными свойствам, работает, назначая пустое значение вместо пустого экземпляра коллекции, чтобы вызвать упомянутое исключение. Это то же самое независимо от ограничений обнуляемости для ключевого столбца.
Я не знаю, считается ли это преднамеренным поведением, поскольку обычно нулевые значения действуют так же, как пустые коллекции. Я посмотрю, смогу ли я узнать об этом больше, а затем, возможно, выложу отчет об ошибке.
обновление: проблема на https://hibernate.atlassian.net/browse/HHH-7726
Это не полностью отвечает на ваш вопрос, но я надеюсь, что это может немного помочь.
Во-первых, я бы порекомендовал вам взглянуть на это объяснение, а также на это.
Теперь вы сами сказали, что дочерние объекты не ссылаются на родителя, и что это односторонние отношения. Я не знаю, какой вид картирования вы придумали, но это:
Parent parent = new Parent();
parent.setChildren(Collections.singleton(new Child())));
session.save(parent);
// this correctly results in:
// SQL> INSERT INTO PARENT ...
// SQL> INSERT INTO CHILD ...
Работать можно, только если:
cascade
в наборе включено отображение (напримерcascade="all"
иначе Hibernate будет жаловаться на несохраненный временный экземпляр новогоChild
объект)- столбец parent_id имеет значение NULL (иначе Hibernate будет ожидать, что вы зададите это поле, что возможно только в том случае, если у вас есть другая сторона взаимосвязи)
Кроме того, Hibernate сгенерирует еще один SQL UPDATE
в дополнение к этим двум вставкам, которые вы упомянули в комментариях (то, что вы можете увидеть, на самом деле объясняется в ссылках, которые я вам дал).
Надеюсь, ты что-то из этого получишь.