У меня есть сложная сущность:
public class Task {
@OneToOne(orphanRemoval=true, mappedBy = "parent")
@Cascade(value = CascadeType.ALL) (org.hibernate.annotations ... package)
private Executor executor;
...
}
public class Executor {
@OneToOne
@JoinColumn
private Task parent;
@ManyToOne
@Cascade(value = CascadeType.ALL)
private List<Property> propList = new LinkedList<Property>();
}
Как правило, это «Задача», которая формирует «Исполнителя», а «Исполнитель» заполняется некоторыми специфическими свойствами.
Если я делаю это обычным образом, то есть:
@Service
public class Service {
@PostConstruct
private void test() {
Task task = new Task();
Executor ex = new Executor();
List<Property> props = ex.getProperties();
... forming and adding some properties
taskDao.saveAndFlush(task);
}
Все в порядке, и задача сохраняется правильно.
Но так как это упрощено, и мне нужно сохранить Task в тот момент, когда я его получу, то есть сразу после определения, и сохранить его (сброс, без сброса, разделение на отдельный метод с транзакцией),
@Service
public class Service {
@PostConstruct
private void test() {
Task task = new Task();
taskDao.saveAndFlush(task); // no change in the exception if I properly move this out to a separate method with @Transactional
Executor ex = new Executor();
List<Property> props = ex.getProperties();
... forming and adding some properties
taskDao.saveAndFlush(task);
}
Я получаю «несохраненную транзакцию», которая указывает на вторую «saveAndFlush».
И это достижимо только в том случае, если я заполню Свойства, что означает, что закомментировав часть «свойства формирования», все работает хорошо.
Каскад ВСЕ (полный список, хранящийся в org.hibernate.annotations...), поэтому у меня есть сомнения, что я забыл указать «Каскад».




saveAndflush не переводит объект в управляемое состояние, вам необходимо использовать управляемый объект, возвращаемый этим методом. Попробуйте это решение:
@PostConstruct
private void test() {
Task task = new Task();
task = taskDao.saveAndFlush(task); // reassign
Executor ex = new Executor();
List<Property> props = ex.getProperties();
... forming and adding some properties
taskDao.saveAndFlush(task);
}
Не говорите мне, что я застрял между удалением детей и «всеми остальными» вещами :)
Это все, что приходит мне в голову, попробуйте, и я постараюсь придумать что-нибудь получше, чем это ;)
Да, этот я тоже пробовал несколько раз. Даже при сохранении применялся избыточный подход, затем выборка сохраненного элемента по сформированному идентификатору, а затем повторная попытка (даже с отдельным методом для сохранения и возврата, который запрашивал сущность по сформированному идентификатору.
Что ж, я только что попробовал это на другом наборе сущностей, и оказалось, что проблема каким-то образом заключается в текущих сущностях, которые я использую (которые немного запутаны с точки зрения DDL).
Да, еще раз ошибкой было определение объекта (таблица позади объекта была разработана... кем-то случайным образом). Неправильное определение в определении свойства, относящееся к родительскому объекту. Исправил и все пошло хорошо.
БД - это MySQL, а @OneToMany(cascade = CascadeType.ALL) не распространяется на "CascadeType.REMOVE", что затрудняет каскадное удаление дочерних элементов.