Спящий режим: OneToMany спасает детей каскадом
В классе Parent есть список List. Когда родитель сохраняется, дочерние элементы, которые были добавлены или изменены, должны быть сохранены/обновлены с помощью спящего режима.
Я нашел много объяснений по этому поводу, однако, я просто не понимаю, как это работает.
Parent.class попробуйте A
@Entity
public class Parent {
// id and other attributes
@OneToMany(mappedBy = "parent")
@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.ALL)
protected List<child> children;
Parent.class попробуйте B
@Entity
public class Parent {
// id and other attributes
@OneToMany(mappedBy = "parent", cascade = { javax.persistence.CascadeType.ALL },
orphanRemoval = true)
@org.hibernate.annotations.Cascade({
org.hibernate.annotations.CascadeType.PERSIST,
org.hibernate.annotations.CascadeType.MERGE,
org.hibernate.annotations.CascadeType.REFRESH,
org.hibernate.annotations.CascadeType.SAVE_UPDATE,
org.hibernate.annotations.CascadeType.REPLICATE,
org.hibernate.annotations.CascadeType.LOCK,
org.hibernate.annotations.CascadeType.DETACH })
protected List<child> children;
дети добавляются к новому родителю. Впоследствии оба сохраняются
sessionFactory.getCurrentSession().saveOrUpdate(parent);
при промывке я получаю следующую ошибку:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: de.pockettaxi.backend.model.ride.RideSingle
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:243)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:456)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:265)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:275)
at org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:295)
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:3378)
at org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:520)
at org.hibernate.event.def.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:230)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
Кто-нибудь видит мою ошибку?
Большое спасибо!
Ответы
Ответ 1
Я думаю, если вы ответите на вопрос с первого комментария, мы придем к этой ситуации:
- у вас уже сохраненный родитель
- у вас есть новые дочерние объекты, которые еще не были сохранены.
- вы добавляете дочерние элементы в родительский элемент и сохраняете saveOrUpdate
В этом случае hibernate просто каскадирует сохранение или обновление для детей, но они не могут быть сохранены или обновлены, поскольку они еще не были постоянными. И теперь Hibernate просто говорит: "Я не могу обновить непостоянную сущность"
В одном предложении: Hibernate только каскадирует то, что выдается каскаду. В этом случае вы выдаете "SAVE_UPDATE" , который затем каскадируется потом детям. Думаю, вы ожидали, что Hibernate будет умным и переключится на детей здесь. Но здесь не работает Hibernate, я тоже сталкивался с подобными ситуациями. Немного сбивает с толку, но если вы когда-нибудь узнаете, как работает каскадный процесс, вы увидите такие ситуации.
Ответ 2
Мне понадобился способ вставить объект вместе с новым объединенным (дочерним) объектом. Один из способов сделать это - разделить действия (например, сначала сохранить объединенный объект, а затем сохранить основной объект).
Тем не менее, Hibernate поддерживает вставку нового объекта с новым объединенным объектом.
См. Один пример: Как вставить детей OneToMany по каскаду
Ответ 3
Ваша попытка Parent.class A кажется уже правильной. Но чтобы каскадировать ребенка при сохранении родителя, вы должны поставить каскад на стороне владельца (в один ко многим, это сущность, которая имеет внешний ключ).
Попробуйте это
@Entity
public class Parent {
@OneToMany(mappedBy = "parent")
protected List<Child> children;
}
и в вашем Child.class
@Entity
public class Child {
@ManyToOne
@Cascade(value={org.hibernate.annotations.CascadeType.ALL})
@JoinColumn(name="PARENT_ID")
protected Parent parent;
}
Ответ 4
Попробуйте следующее:
@Entity
@Table(name = "TABLE_PARENT")
public class Parent{
@OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST)
private List<Child> children;
}
@Entity
@Table(name = "TABLE_CHILD")
public class Child{
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="PARENT_ID")
private Parent parent;
}
Использование
public void save(){
Parent parent = new Parent();
List<Child> children = new ArrayList<>();
Child child = new Child();
child.setParent(parent);
children.add(child);
parent.setChildren(children);
parentRepository.save(parent);
}
Примечание. Не забудьте установить родительский объект в дочернем объекте или вы получите TABLE_CHILD.PARENT_ID null/empty