我正在使用 Hibernate 3,并且在持久化与现有分离实体有关联的新实体时遇到特定问题。解释这一点的最简单方法是通过代码示例。我有两个实体,FooEntity 和 BarEntity,其中一个 BarEntity 可以与许多 FooEntity 相关联:
@Entity
public class FooEntity implements Foo{
@Id
private Long id;
@ManyToOne(targetEntity = BarEntity.class)
@JoinColumn(name = "bar_id", referencedColumnName = "id")
@Cascade(value={CascadeType.ALL})
private Bar bar;
}
@Entity
public class BarEntity implements Bar{
@Id
private Long id;
@OneToMany(mappedBy = "bar", targetEntity = FooEntity.class)
private Set<Foo> foos;
}
Foo 和 Bar 是为各种字段松散定义 getter 的接口。有相应的 FooImpl 和 BarImpl 类,它们本质上只是没有注释的实体对象。
我要做的是构造一个新的 FooImpl 实例,并在设置多个字段后将其持久化。新的 Foo 实例会将其“bar”成员设置为来自数据库(通过 session.get(..) 检索)的现有 Bar(运行时是 BarEntity)。在 FooImpl 设置完所有属性后,Apache Dozer 用于在“域”对象 FooImpl 和实体 FooEntity 之间进行映射。Dozer 在后台所做的是实例化一个新的 FooEntity 并设置所有匹配的字段。BarEntity 也通过实例化克隆并设置 FooEntity 的“bar”成员。
发生这种情况后,将新的 FooEntity 对象传递给持久化。这会引发异常:
org.hibernate.PersistentObjectException: detached entity passed to persist: com.company.entity.BarEntity
以下是正在发生的步骤的代码
FooImpl foo = new FooImpl();
//returns at runtime a persistent BarEntity through session.get()
Bar bar = BarService.getBar(1L);
foo.setBar(bar);
...
//This constructs a new instance of FooEntity, with a member 'bar' which itself is a new instance that is detached)
FooEntity entityToPersist = dozerMapper.map(foo, FooEntity.class);
...
session.persist(entityToPersist);
我已经能够通过删除或更改 @Cascade 注释来解决这个问题,但这限制了未来的使用,比如添加一个新的 Foo 已经附加了一个新的 Bar 。我在这里缺少一些解决方案吗?如果这个问题以前没有在某个地方得到解决,我会感到惊讶,无论是通过改变 Dozer 如何映射 Foo 的子级或 Hibernate 如何对分离的子实体做出反应。