okay, maybe more info would help. I have stripped down the problem to a simple test. The code for all this follows. orphaning a child from the parent does not update the database here such that the child no longer relates to the parent(I am not trying to delete the child, just orphan it).
first the test.....
Code:
public void testOrphanChildOnPurpose() {
String child2Name = setupDb();
EntityManager mgr = openSession();
mgr.getTransaction().begin();
Query q = mgr.createNamedQuery("getParents");
@SuppressWarnings("all")
List<ParentDBO> parents = q.getResultList();
assertEquals("There should be only one", 1, parents.size());
Query q2 = mgr.createNamedQuery("getChild");
q2.setParameter("name", child2Name);
ChildDBO childToRemove = (ChildDBO)q2.getSingleResult();
ParentDBO parent = parents.get(0);
Collection<ChildDBO> children = parent.getChildren();
assertEquals("Should be 2 children", 2, children.size());
children.remove(childToRemove);
assertEquals("Should have removed a child", 1, children.size());
mgr.merge(parent);
mgr.getTransaction().commit();
mgr.close();
}
private String setupDb() {
EntityManager mgr = openSession();
mgr.getTransaction().begin();
String child2Name="anotherChild";
ParentDBO parent = new ParentDBO();
parent.setName("parent");
ChildDBO child = new ChildDBO();
child.setName("child");
parent.addChild(child);
ChildDBO child2 = new ChildDBO();
child2.setName(child2Name);
parent.addChild(child2);
//in the hibernate logs, this should result in 2 inserts and no updates but results
//in one update still!!!
mgr.merge(parent);
mgr.getTransaction().commit();
mgr.close();
return child2Name;
}
Now the entire ParentDBO bean...
Code:
@Entity
@Table( name = "Parents")
@NamedQueries(
{
@NamedQuery(name="getParents", query="SELECT c FROM ParentDBO c")
})
public class ParentDBO {
private Long id;
private int version;
private String name;
private Collection<ChildDBO> children;
@Column(name="Id")
@Id()
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
@SuppressWarnings("all")
private void setId(Long id) {
this.id = id;
}
@Version
@Column(name="Version", nullable=false)
public int getVersion() {
return version;
}
@SuppressWarnings("all")
private void setVersion(int version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name="parent_id")
@OneToMany(mappedBy="parent", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
public Collection<ChildDBO> getChildren() {
if(children == null) {
children = new ArrayList<ChildDBO>();
}
return children;
}
public void setChildren(Collection<ChildDBO> children) {
this.children = children;
}
public void addChild(ChildDBO child) {
if(child == null)
throw new IllegalArgumentException("child may not be null and was");
else if(child.getParent() != null)
child.getParent().getChildren().remove(child);
child.setParent(this);
getChildren().add(child);
}
public void removeChild(ChildDBO child) {
if(child == null)
throw new IllegalArgumentException("child may not be null and was");
else if(!getChildren().contains(child))
throw new IllegalArgumentException("Parent does not contain this child");
child.setParent(null);
getChildren().remove(child);
}
}
Now the entire ChildDBO bean....
Code:
@Entity
@Table( name = "Children")
@NamedQueries(
{
@NamedQuery(name="getChild", query="SELECT c FROM ChildDBO c WHERE c.name = :name")
})
public class ChildDBO {
private Long id;
private int version;
private String name;
private ParentDBO parent;
@Column(name="Id")
@Id()
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
@SuppressWarnings("all")
private void setId(Long id) {
this.id = id;
}
@Version
@Column(name="Version", nullable=false)
public int getVersion() {
return version;
}
@SuppressWarnings("all")
private void setVersion(int version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne
@JoinColumn(name="parent_id")
public ParentDBO getParent() {
return parent;
}
public void setParent(ParentDBO parent) {
this.parent = parent;
}
@Override
public boolean equals(Object rightSide) {
if(!(rightSide instanceof ChildDBO))
return false;
ChildDBO child = (ChildDBO)rightSide;
if(!id.equals(child.id))
return false;
return true;
}
@Override
public int hashCode() {
return (int)(id / 2);
}
}
[/code]