Using the slightly modified version of example from HibernateAnnotations test code, I have an entity Boy that has a CollectionOfElements of Toy (that has 2 simple string attributes).
The test case is as follows:
(1) I persist a Boy entiry with a collection of 2 Toy elements. One of the elements has a null value for "brand" attribute.
(2) I load the entity from database - which immediately loads the 2 elements in the collection, they being values.
(3) I remove the element that has NULL brand from the collection and commit.
The sql statements below show that a delete is being issued. However the corresponding row does not get deleted from database. This is verified when the third code block containing assert fails.
I believe the reason is that the WHERE clause is incorrect:
What is generated (shown below) is
delete from Boy_toys where Boy_id=? and name=? and brand=?
This should instead be
delete from Boy_toys where Boy_id=? and name=? and brand is NULL
Note: There is no problem deleting element where all attributes are NOT null.
Hibernate version:
Hibernate 3.2 cr2
Hibernate EntityManager 3.2.0.CR1
Hibernate Annotations 3.2.0.CR1
Mapping documents:
Annotated classes shown below:
@Entity
public class Boy {
@Id
@GeneratedValue
public Integer id;
public String firstName;
public String lastName;
@CollectionOfElements
public Set<Toy> toys = new HashSet<Toy>();
public Boy() {
}
public Boy(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
@Embeddable
public class Toy {
public String name;
public String brand;
public Toy() {
}
public Toy(String name, String brand) {
this.name = name;
this.brand = brand;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Toy)) return false;
final Toy toy = (Toy) o;
if (brand != null ? !brand.equals(toy.brand) : toy.brand != null) return false;
if (name != null ? !name.equals(toy.name) : toy.name != null) return false;
return true;
}
public int hashCode() {
int result;
result = (name != null ? name.hashCode() : 0);
result = 29 * result + (brand != null ? brand.hashCode() : 0);
return result;
}
}
Code between sessionFactory.openSession() and session.close():
// save boy with 2 toys
tx = em.getTransaction();
tx.begin();
Boy b = new Boy("first name", "last name");
b.toys.add(new Toy("toy1", null));
b.toys.add(new Toy("toy2", "brand2"));
em.persist(b);
tx.commit();
// delete toy with null brand
em.clear();
tx.begin();
b = em.find(Boy.class, b.id);
Iterator it = b.toys.iterator();
it.next();
Toy t = (Toy) it.next();
System.out.println("deleted toy: name=" + t.name + ", brand=" + t.brand);
it.remove();
tx.commit();
// verify that there is only one toy left --- this fails
em.clear();
b = em.find(Boy.class, b.id);
assertEquals(1, b.toys.size());
Full stack trace of any exception that occurs:
no exception raised
Name and version of the database you are using:
MySql 5.0
The generated SQL (show_sql=true):
21:12:09,790 DEBUG SQL:393 - insert into Boy (firstName, lastName) values (?, ?)
21:12:09,841 DEBUG SQL:393 - insert into Boy_toys (Boy_id, name, brand) values (?, ?, ?)
21:12:09,851 DEBUG SQL:393 - insert into Boy_toys (Boy_id, name, brand) values (?, ?, ?)
21:12:09,911 DEBUG SQL:393 - select boy0_.id as id0_0_, boy0_.firstName as firstName0_0_, boy0_.lastName as lastName0_0_ from Boy boy0_ where boy0_.id=?
21:12:09,921 DEBUG SQL:393 - select toys0_.Boy_id as Boy1_0_, toys0_.name as name0_, toys0_.brand as brand0_ from Boy_toys toys0_ where toys0_.Boy_id=?
deleted toy: name=toy1, brand=null
21:12:10,031 DEBUG SQL:393 - delete from Boy_toys where Boy_id=? and name=? and brand=?
21:12:10,031 DEBUG SQL:393 - select boy0_.id as id0_0_, boy0_.firstName as firstName0_0_, boy0_.lastName as lastName0_0_ from Boy boy0_ where boy0_.id=?
21:12:10,031 DEBUG SQL:393 - select toys0_.Boy_id as Boy1_0_, toys0_.name as name0_, toys0_.brand as brand0_ from Boy_toys toys0_ where toys0_.Boy_id=?
junit.framework.AssertionFailedError: expected:<1> but was:<2>
Debug level Hibernate log excerpt:
|