У меня двунаправленная связь @OneToOne между родительскими и дочерними объектами, с @MapsId для совместного использования первичного ключа.
С помощью родительского объекта я могу добавить дочерний объект, удалить его, а затем добавить новый дочерний объект. object:
Parent parent = new Parent();
parent.name = "parent";
Child child = new Child();
child.name = "child";
child.parent = parent;
parent.child = child;
manager.persist(parent);
manager.flush();
// Replace this block with ?
parent.child = null;
child.parent = null;
manager.persist(parent);
manager.flush();
Child child2 = new Child();
child2.name = "child2";
child2.parent = parent;
parent.child = child2;
manager.persist(parent);
Но, есть ли способ установить новый дочерний объект, не удаляя (и не стирая) старый?
Если я удаляю flush()
из среднего блока, Hibernate жалуется, что идентификатор уже связан с сеансом. Я думаю, что я ищу способ сказать Hibernate игнорировать старую сущность Child, позволить новой иметь тот же идентификатор и запустить обновление SQL для нового Child вместо insert.
Я понимаю,Я могу просто обновить текущие дочерние поля, но я хотел бы знать, возможна ли полная замена объекта.
Полный код, показывающий определения сущностей, находится здесь:
import javax.persistence.*;
public class OneToOneExample {
@Entity(name = "Parent")
public static class Parent {
@Id
@GeneratedValue
Long id;
@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
Child child;
String name;
}
@Entity(name = "Child")
public static class Child {
@Id
Long id;
@OneToOne
@MapsId
Parent parent;
String name;
}
private static void runExample(EntityManager manager) {
Parent parent = new Parent();
parent.name = "parent";
Child child = new Child();
child.name = "child";
child.parent = parent;
parent.child = child;
manager.persist(parent);
manager.flush();
// Replace this block with ?
parent.child = null;
child.parent = null;
manager.persist(parent);
manager.flush();
Child child2 = new Child();
child2.name = "child2";
child2.parent = parent;
parent.child = child2;
manager.persist(parent);
}
public static void main(String[] args) {
EntityManagerFactory factory = null;
EntityManager manager = null;
try {
factory = Persistence.createEntityManagerFactory(OneToOneExample.class.getPackageName());
manager = factory.createEntityManager();
manager.getTransaction().begin();
runExample(manager);
manager.getTransaction().commit();
} finally {
if (manager != null) manager.close();
if (factory != null) factory.close();
}
}
}
Исключение:
Exception in thread "main" javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [....OneToOneExample$Child#1]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:123)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:733)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:695)
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:298)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:492)
at ...
Я использую Hibernate 5.4.6.Final, Hibernate-JPA2.11.0.2.Final, HSQLDB 2.5.0
Обновление: исходное поколение Hibernate SQL и данные таблицы:
Hibernate: drop table if exists Child CASCADE
Hibernate: drop table if exists Parent CASCADE
Hibernate: drop sequence hibernate_sequence if exists
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: create table Child (name varchar(255), parent_id bigint not null, primary key (parent_id))
Hibernate: create table Parent (id bigint not null, name varchar(255), primary key (id))
Hibernate: alter table Child add constraint FKlh67j1n7x7gt59u0pbkwqh6o6 foreign key (parent_id) references Parent
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Parent (name, id) values (?, ?)
Hibernate: insert into Child (name, parent_id) values (?, ?)
Hibernate: delete from Child where parent_id=?
Hibernate: insert into Child (name, parent_id) values (?, ?)
SELECT * FROM CHILD
NAME, PARENT_ID
child2, 1
SELECT * FROM PARENT
ID, NAME
1, parent