JPA2 Lazy Child Collection with orphanRemoval=true deletes 'not-fetched' children
I have a Parent entity that owns(via mappedBy) a FetchType.LAZY Set<Child> with orphanDe开发者_高级运维lete=true.
A client can happily add and remove child rows via the parent's collection getter and their changes are properly committed after an em.merge(parent).
However, if a client merges a parent WITHOUT accessing the child collection, all child rows are deleted on the parent's commit.
The same behavior is exhibited under OpenJPA 2.1.0 and the 2.1.1-20110610.205956-18 snapshot binary.
Any pointers would be appreciated.
An example to illustrate:
@Entity
public class Parent{
@Column
private String name;
@OneToMany(mappedBy="parent", fetch=LAZY, cascade = ALL, orphanRemoval=true)
private Set<Child> children;
public String getName(){return name;}
public void setName(String name){this.name=name;}
public Set<Child> getChildren(){
return children;
}
}
@Entity
public class Child{
@ManyToOne(optional = false, targetEntity = Parent.class)
@JoinColumn(name="parent_id", nullable=false)
private Parent parent;
}
Both entities have @Id and @Version properties declared and implement appropriate hashCode, equals and compareTo methods.
The following client code works perfectly, the parent.name is updated, 1 child is inserted and 1 child is deleted
EntityTransaction eTx=em.getTransaction();
eTx.begin();
Parent par=em.find(Parent.class, parId);
//PersistenceUnitUtil.isLoaded(par) returns true
//PersistenceUnitUtil.isLoaded(par, "children") returns false
Collection<Child> children=par.getChildren();
//PersistenceUnitUtil.isLoaded(par, "children") returns true
Child child = children.iterator().next();
par.getChildren().remove(child);
par.getChildren().add(new Child(par, "I'm New"));
par.setName("I am Updated");
par=em.merge(par);
eTx.commit();
The following code will issue delete commands for each of the parent's children:
EntityTransaction eTx=em.getTransaction();
eTx.begin();
Parent par=em.find(Parent.class, parId);
//PersistenceUnitUtil.isLoaded(par) here returns true, and
//PersistenceUnitUtil.isLoaded(par, "children") returns false
par.setName("I am Updated");
par=em.merge(par);
eTx.commit();
Just don't call merge. There's no need for it. Within the scope of a transaction, changes made to an object that was looked up within that transaction will be persisted unless the object is detached.
精彩评论