Вы получаете это, потому что вы пытаетесь сохранить объект, который уже существует (тот же идентификатор). Ваш каскад, вероятно, не сохраняется, это MERGE / UPDATE / REMOVE / DETACH. Лучший способ избежать этой ситуации - правильно настроить каскад или управлять каскадами вручную. В сущности, каскадирование является обычным виновником.
Вы, вероятно, хотите что-то вроде этого:
//SomeService--I assume you create ID's on persist
saveChild(Parent parent, Child child)
{
//Adding manually (using your cascade ALL)
if(child.getId() == null) //I don't exist persist
persistence.persist(child);
else
persistence.merge(child); //I'm already in the DB, don't recreate me
parent.setChild(child);
saveParent(parent); //using a similar "don't duplicate me" approach.
}
Каскады могут быть крайне разочаровывающими, если вы позволяете платформе управлять ею, потому что вы иногда пропускаете обновления, если она кэшируется (особенно с отношениями Collections in ManyToOne). Если вы явно не сохраняете родительский объект и не позволяете платформе работать с каскадами. Вообще говоря, я разрешаю Cascade.ALL от моих родителей в отношениях и каскад всего из DELETE / PERSIST от моих детей. Я пользователь Eclipselink, поэтому мой опыт работы с Hibernate / other ограничен, и я не могу говорить с кешированием.
* Действительно, подумайте об этом - если вы спасаете ребенка, вы действительно хотите сохранить все объекты, связанные с ним? Кроме того, если вы добавляете ребенка, не должны ли вы уведомить родителя? *
В вашем случае у меня просто был бы метод "saveParent" и "saveChild" в моем Dao / Service, который проверял правильность кэша и базы данных во избежание головной боли. Управление вручную означает, что вы будете иметь абсолютный контроль и вам не придется полагаться на каскады, чтобы выполнять свою грязную работу. В однонаправленном направлении они фантастические, в ту минуту, когда они выходят «вверх по течению», вы можете столкнуться с неожиданным поведением.