Dear Hibernate Developers
[I have already talked to Vlad about this problem|https://forum.hibernate.org/viewtopic.php?f=1&t=1044827&p=2493417#p2493417]
Hibernate triggers unnecessary update statements for all previous elements of a map if a new element is being added to this map. The problem only occures for maps with bidirectional bindings and HBM XML mappings. I was unable to reproduce the issue with annotation based mappings or unidirectional bindings.
I built a simple demo projects containing two classes for illustration purposes. A person object referencing one or more task objects.
Person.hbm.xml {code:xml} <hibernate-mapping> <class name="persistency.test.Person" table="person" lazy="true"> <id name="dbKey" type="long" access="field" column="dbkey"> <generator class="native" /> </id>
<property name="name" type="java.lang.String" length="20" access="field" />
<map name="tasks" cascade="all-delete-orphan" inverse="true" access="field"> <key column="person_dbkey" /> <map-key type="string" column="name" /> <one-to-many class="persistency.test.Task" /> </map> </class> </hibernate-mapping> {code}
Person.java {code:java} public class Person {
private String name; private long dbKey;
private Map<String, Task> tasks = new HashMap<>();
public void addTask(Task task) { task.setOwner(this); this.tasks.put(task.getName(), task); } } {code}
Task.hbm.xml {code:xml} <hibernate-mapping> <class name="persistency.test.Task" table="task" lazy="true"> <id name="dbKey" type="long" access="field" column="dbkey"> <generator class="native" /> </id>
<property name="name" type="java.lang.String" length="20" access="field" /> <property name="description" type="java.lang.String" length="100" access="field" />
<many-to-one name="owner" column="person_dbkey" class="persistency.test.Person" access="field" />
</class> </hibernate-mapping>{code}
Task.java {code:java} public class Task {
private String name; private long dbKey; private Person owner; private String description;
public Task(String name, String description) { this.name = name; this.description = description; }
public Task() { }
public String getName() { return name; }
public void setOwner(Person owner) { this.owner = owner; } } {code}
The table Task already contains three tasks: {noformat} DBKEY | NAME | PERSON_DBKEY | DESCRIPTION 221000 | Eating | 139000 | Food 218000 | Cooking | 139000 | Food 225000 | Reading | 139000 | Food {noformat}
If a new task is being added to the map containg already three tasks: {code:java} session.beginTransaction(); Person person = session.load(Person.class, 139000l); person.addTask(new Task("Cleaning", "Floor, Roof"));
session.getTransaction().commit(); {code}
Hibernate then executes the following SQL statements:
{code:sql} select person0_.dbkey as dbkey1_0_0_, person0_.name as name2_0_0_ from XHM_2.person person0_ where person0_.dbkey=? select tasks0_.person_dbkey as person_dbkey4_1_0_, tasks0_.dbkey as dbkey1_1_0_, tasks0_.name as name2_0_, tasks0_.dbkey as dbkey1_1_1_, tasks0_.name as name2_1_1_, tasks0_.description as description3_1_1_, tasks0_.person_dbkey as person_dbkey4_1_1_ from XHM_2.task tasks0_ where tasks0_.person_dbkey=?
select XHM_2.hibernate_sequence.nextval from dual insert into XHM_2.task (name, description, person_dbkey, dbkey) values ('Cleaning', 'Floor, Roof', '139000', '224000') update XHM_2.task set name='Eating' where dbkey='221000' update XHM_2.task set name='Cooking' where dbkey='218000' update XHM_2.task set name='Reading' where dbkey='225000' update XHM_2.task set name='Cleaning' where dbkey='224000' {code}
Hibernate triggers for four update statements as shown above. I think there is no reason to update the previous three elements and the newly added element either. |
|