我在父级和子级实体之间有一个双向@OneToOne关联,并带有@MapsId来共享主键。
对于父对象,我可以添加一个子对象,将其删除,然后添加一个新的子对象:
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);
但是,有没有一种方法可以设置一个新的Child对象,而不删除(并刷新)旧的Child对象?
如果我从中间块中删除flush()
,则Hibernate会抱怨该标识符已经与会话关联。我想我正在寻找一种方法来告诉Hibernate忽略旧的Child实体,允许新的实体具有相同的ID,并为新的Child运行SQL更新而不是插入。
我意识到我可以只更新当前的Child字段,但是我想知道是否可以进行完整的对象替换。
显示实体定义的完整代码在这里:
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.1 1.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