I have created a test case to highlight what I am seeing, but I see that I am unable to post a zip file here containing the test case. If anyone is interested in seeing the test case I can either post it all, or send it via email.
Let me post it here, so that you can see what I mean:
Code:
@Entity
@Table(name = "PARENT")
public class Parent implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Set<Child> children = new HashSet<Child>();
/**
*
*/
public Parent() {
}
@Id
@Column(name = "ID", nullable = false, precision = 8, scale = 0)
@GeneratedValue(generator = "PARENT_SEQ", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "PARENT_SEQ", sequenceName = "parent_seq", allocationSize = 1)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "NAME_", length = 128)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "owner")
public Set<Child> getChildren() {
return children;
}
public void setChildren(Set<Child> children) {
this.children = children;
}
}
Code:
@Entity
@Table(name = "CHILD")
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Parent owner;
private Set<Grandchild> grandchildren = new HashSet<Grandchild>();
/**
*
*/
public Child() {
}
@Id
@Column(name = "ID", nullable = false, precision = 8, scale = 0)
@GeneratedValue(generator = "CHILD_SEQ", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "CHILD_SEQ", sequenceName = "child_seq", allocationSize = 1)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "NAME_", length = 128)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "OWNER_ID", nullable = false)
public Parent getOwner() {
return owner;
}
public void setOwner(Parent owner) {
this.owner = owner;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "owner")
public Set<Grandchild> getGrandchildren() {
return grandchildren;
}
public void setGrandchildren(Set<Grandchild> grandchildren) {
this.grandchildren = grandchildren;
}
}
Code:
@Entity
@Table(name = "GRANDCHILD")
public class Grandchild implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Child owner;
/**
*
*/
public Grandchild() {
}
@Id
@Column(name = "ID", nullable = false, precision = 8, scale = 0)
@GeneratedValue(generator = "GRANDCHILD_SEQ", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "GRANDCHILD_SEQ", sequenceName = "grandchild_seq", allocationSize = 1)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "NAME_", length = 128)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "OWNER_ID", nullable = false)
public Child getOwner() {
return owner;
}
public void setOwner(Child owner) {
this.owner = owner;
}
}
Code:
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.autocommit">false</property>
<mapping class="testcases.model.Parent"/>
<mapping class="testcases.model.Child"/>
<mapping class="testcases.model.Grandchild"/>
</session-factory>
</hibernate-configuration>
And now here is the test (written in TestNG):
Code:
public class Testing {
/**
*
*/
public Testing() {
// TODO Auto-generated constructor stub
}
@BeforeSuite
public void setup() {
HibernateUtils.getInstance().createDatabase();
}
@BeforeTest
public void setupData() {
Session session = HibernateUtils.getInstance().getNewSession();
session.beginTransaction();
for (int i=0; i<10; i++) {
Parent parent = new Parent();
parent.setName("Parent_" + i);
for (int j=0; j<10; j++) {
Child child = new Child();
child.setName("Child_" + j);
child.setOwner(parent);
parent.getChildren().add(child);
for (int k=0; k<10; k++) {
Grandchild grandchild = new Grandchild();
grandchild.setName("Grandchild_" + k);
grandchild.setOwner(child);
child.getGrandchildren().add(grandchild);
}
}
session.persist(parent);
}
session.getTransaction().commit();
session.flush();
}
@Test
public void test1() {
Assert.assertTrue(ensureParentCount(10));
Assert.assertTrue(ensureChildCount(10 * 10));
Assert.assertTrue(ensureGrandchildCount(10 * 10 * 10));
Session session = HibernateUtils.getInstance().getNewSession();
session.beginTransaction();
Parent parent = (Parent) session.createCriteria(Parent.class).add(Restrictions.eq("name", "Parent_5")).uniqueResult();
Child child = (Child) session.createFilter(parent.getChildren(), "WHERE this.name = :PARAM0").setString("PARAM0", "Child_5").uniqueResult();
List<Grandchild> grandchildren = new ArrayList<Grandchild>(child.getGrandchildren());
for (int i=0; i<5; i++) {
child.getGrandchildren().remove(grandchildren.get(i));
}
session.update(parent);
session.getTransaction().commit();
session.flush();
Assert.assertTrue(ensureGrandchildCount((10 * 10 * 10) - 5));
}
private boolean ensureParentCount(int count) {
Session session = HibernateUtils.getInstance().getNewSession();
try {
return session.createCriteria(Parent.class).list().size() == count;
} finally {
session.close();
}
}
private boolean ensureChildCount(int count) {
Session session = HibernateUtils.getInstance().getNewSession();
try {
return session.createCriteria(Child.class).list().size() == count;
} finally {
session.close();
}
}
private boolean ensureGrandchildCount(int count) {
Session session = HibernateUtils.getInstance().getNewSession();
try {
return session.createCriteria(Grandchild.class).list().size() == count;
} finally {
session.close();
}
}
As you can see from the test, I am trying to remove 5 grandchildren, and then execute the save, but it doesn't pick up that there is a change, and the last test fails.