假设我有以下Java ORM映射:
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
@OneToOne
private Address workAddress;
@OneToOne
private Address homeAddress;
}
@Entity
public class Address {
@Id
@GeneratedValue
private Long id;
}
假设给定Person
实例是使用相同的持久化Address
实例创建的。例如:
@Transactional
public void reuseAddressInPerson() {
Address address = new Address();
// fill address values
address = em.persist(address);
Person person = new Person();
person.workAddress = address;
person.homeAddress = address;
em.persist(person);
}
基于此,当我person
使用休眠方式加载该持久化对象时,workAddress
和的地址实例homeAddress
在person
对象中将是相同的引用。有一些方法可以使休眠状态address
在调用em.find()
?时为每个对象创建新实例。
注意:我已经创建了这个示例来说明我的问题,但是在实际情况下,使用克隆(或类似方法)准备该对象是不实际的。
显然,hibernate没有提供任何现成的机制来管理实体引用。因此,我找到了使用的方法ObjectOutputStream
。该引擎需要两个步骤,第一步是从数据库中加载实体并清除持久性上下文,第二步是在对象结构中搜索应该克隆什么实体以驱逐共享引用。为了解释它是如何工作的,我们将使用与问题相同的人员地址模型。
第1步-加载实体
public Person loadProject() {
// First we load person from database
Person person = personRepository.getOne(personId);
// Then we clear the persistence context to evict detached exceptions
entityManager.clear();
person = (Person) Hibernate.unproxy(person); // Remove proxies from the object
// Now we call Step 2 (clone shared references)
person = entityReferencesService.cloneAddressReferences(person);
return person;
}
第2步-克隆共享引用
public class EntityReferencesService {
//...
public Person cloneAddressReferences(Person person) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos) {
{
enableReplaceObject(true); // Allows objects to be replaced during serialization
}
@Override
protected Object replaceObject(Object obj) throws IOException {
Object replacedObject = obj;
// This code could be smart to known what entities to clone
if (obj instanceof Person) {
Person p = (Person) obj;
// using apache bean commons
p.workAddress = SerializationUtils.clone(p.workAddress);
p.homeAddress = SerializationUtils.clone(p.homeAddress);
}
return replacedObject;
}
};
oos.writeObject(person);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Person) ois.readObject();
} catch (Exception ex) {}
}
}
此示例过于简化。但是对于复杂的场景,在该replaceObject
方法中,此代码应使用接口或批注来了解哪些实体会克隆。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句