I was directed here from jira:
http://opensource2.atlassian.com/projec ... e/HHH-1196
so here go the gory details...
Hibernate version: Hibernate 3.1 rc3
Mapping documents:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="update" default-access="field">
<class name="Category" table="category">
<id name="id"><generator class="native"/></id>
<version name="version"/>
<property name="description" not-null="true" column="description"/>
<many-to-one name="parent" column="parent_id" cascade="persist"/>
<set name="children" inverse="true" cascade="all">
<key column="parent_id"/>
<one-to-many class="Category"/>
</set>
</class>
</hibernate-mapping>
The class:Code:
public class Category implements Serializable
{
private Long id;
private int version;
private String description;
private Category parent;
private Set<Category> children = new HashSet<Category>();
public Category() {}
public Category(Category parent) {
this.parent = parent;
parent.add(this);
}
public Long id() { return id; }
public int version() { return version; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public Set<Category> children() { return Collections.unmodifiableSet(children); }
public void detach() {
if (parent != null)
parent.remove(this);
}
protected void add(Category child) {
children.add(child);
}
public void remove(Category child) {
children.remove(child);
}
public String toString() { return description; }
private static final long serialVersionUID = 1L;
}
Code between sessionFactory.openSession() and session.close():Code:
Category root = new Category();
root.setDescription("Root Category");
Category c1 = new Category(root);
c1.setDescription("Child #1");
Category c2 = new Category(root);
c2.setDescription("Child #2");
session.save(root); session.flush(); session.clear();
root = (Category)session.load(Category.class, root.id());
Category c = root.children().iterator().next();
root.remove(c);
session.delete(c);
session.flush();
Hibernate issues these SQL statements:
- an update for the root entity incrementing the version
that's ok because the set of children has changed
- an unnecessary update for the child entity to be deleted
this update changes no fields (even version) and IMO is unnecessary
- the deletes for the chilren of deleted child (if any)
- the delete for deleted child
That unnecessary update is executed even when deleted child has no children.
Its children collection is changed from empty set to null
and that is detected as property change, hence the update.
A better strategy would be not to update entities that are going to be
deleted during the flush.
Name and version of the database you are using: HSQL
The generated SQL (show_sql=true):Code:
Hibernate:
insert
into
category
(version, description, parent_id, id)
values
(?, ?, ?, null)
19:31:00,187 DEBUG IntegerType:79 - binding '0' to parameter: 1
19:31:00,203 DEBUG StringType:79 - binding 'Root Category' to parameter: 2
19:31:00,203 DEBUG LongType:71 - binding null to parameter: 3
Hibernate:
call identity()
Hibernate:
insert
into
category
(version, description, parent_id, id)
values
(?, ?, ?, null)
19:31:00,203 DEBUG IntegerType:79 - binding '0' to parameter: 1
19:31:00,203 DEBUG StringType:79 - binding 'Child #2' to parameter: 2
19:31:00,218 DEBUG LongType:79 - binding '1' to parameter: 3
Hibernate:
call identity()
Hibernate:
insert
into
category
(version, description, parent_id, id)
values
(?, ?, ?, null)
19:31:00,218 DEBUG IntegerType:79 - binding '0' to parameter: 1
19:31:00,218 DEBUG StringType:79 - binding 'Child #1' to parameter: 2
19:31:00,218 DEBUG LongType:79 - binding '1' to parameter: 3
Hibernate:
call identity()
Hibernate:
select
category0_.id as id0_0_,
category0_.version as version0_0_,
category0_.description as descript3_0_0_,
category0_.parent_id as parent4_0_0_
from
category category0_
where
category0_.id=?
19:31:00,281 DEBUG LongType:79 - binding '1' to parameter: 1
19:31:00,281 DEBUG IntegerType:123 - returning '0' as column: version0_0_
19:31:00,281 DEBUG StringType:123 - returning 'Root Category' as column: descript3_0_0_
19:31:00,281 DEBUG LongType:116 - returning null as column: parent4_0_0_
Hibernate:
select
children0_.parent_id as parent4_1_,
children0_.id as id1_,
children0_.id as id0_0_,
children0_.version as version0_0_,
children0_.description as descript3_0_0_,
children0_.parent_id as parent4_0_0_
from
category children0_
where
children0_.parent_id=?
19:31:00,296 DEBUG LongType:79 - binding '1' to parameter: 1
19:31:00,296 DEBUG LongType:123 - returning '2' as column: id0_0_
19:31:00,296 DEBUG IntegerType:123 - returning '0' as column: version0_0_
19:31:00,296 DEBUG StringType:123 - returning 'Child #2' as column: descript3_0_0_
19:31:00,296 DEBUG LongType:123 - returning '1' as column: parent4_0_0_
19:31:00,296 DEBUG LongType:123 - returning '1' as column: parent4_1_
19:31:00,296 DEBUG LongType:123 - returning '2' as column: id1_
19:31:00,296 DEBUG LongType:123 - returning '3' as column: id0_0_
19:31:00,296 DEBUG IntegerType:123 - returning '0' as column: version0_0_
19:31:00,296 DEBUG StringType:123 - returning 'Child #1' as column: descript3_0_0_
19:31:00,296 DEBUG LongType:123 - returning '1' as column: parent4_0_0_
19:31:00,296 DEBUG LongType:123 - returning '1' as column: parent4_1_
19:31:00,296 DEBUG LongType:123 - returning '3' as column: id1_
Hibernate:
select
children0_.parent_id as parent4_1_,
children0_.id as id1_,
children0_.id as id0_0_,
children0_.version as version0_0_,
children0_.description as descript3_0_0_,
children0_.parent_id as parent4_0_0_
from
category children0_
where
children0_.parent_id=?
19:31:00,312 DEBUG LongType:79 - binding '3' to parameter: 1
Hibernate:
update
category
set
version=?,
description=?,
parent_id=?
where
id=?
and version=?
19:31:00,312 DEBUG IntegerType:79 - binding '1' to parameter: 1
19:31:00,312 DEBUG StringType:79 - binding 'Root Category' to parameter: 2
19:31:00,312 DEBUG LongType:71 - binding null to parameter: 3
19:31:00,312 DEBUG LongType:79 - binding '1' to parameter: 4
19:31:00,312 DEBUG IntegerType:79 - binding '0' to parameter: 5
Hibernate:
update
category
set
version=?,
description=?,
parent_id=?
where
id=?
and version=?
19:31:00,328 DEBUG IntegerType:79 - binding '0' to parameter: 1
19:31:00,328 DEBUG StringType:79 - binding 'Child #1' to parameter: 2
19:31:00,328 DEBUG LongType:79 - binding '1' to parameter: 3
19:31:00,328 DEBUG LongType:79 - binding '3' to parameter: 4
19:31:00,328 DEBUG IntegerType:79 - binding '0' to parameter: 5
Hibernate:
delete
from
category
where
id=?
and version=?
19:31:00,328 DEBUG LongType:79 - binding '3' to parameter: 1
19:31:00,328 DEBUG IntegerType:79 - binding '0' to parameter: 2