-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Preventing update to non-dirty children associations
PostPosted: Thu Apr 22, 2010 11:33 pm 
Beginner
Beginner

Joined: Sun Oct 14, 2007 7:29 pm
Posts: 23
Hello all,

I'm not a Hibernate expert and cannot seem to resolve this issue. Here is the problem.

I have a three classes named Compdep, Empdep, and Funddep (mappings below) where Compdep is the top level parent with a one-to-many association to Empdep, Empdep has a one-to-many association to Funddep, and Compdep also has a one-to-many association to Funddep. In a stateless session bean (using WebSphere JTA), a Compdep is loaded along with its Empdeps and each Empdep loads its Funddeps. This set of objects is returned to the servlet container for display on a form, so they become detached. When the user saves their changes, my code passes the Compdep and all it's children and grandchildren to the session bean that performs a
Code:
session.update(compDep);
session.flush();


The problem is that the Compdep, all of its children Empdeps, and all of their children Funddeps are updated to the database regardless of whether they changed. If they are not dirty, I would prefer they not be updated to the database to reduce the transaction time and only update those children and grandchildren that are dirty. Is this possible?

I am using the a version identifier on Compdep and Empdep for concurrency (mapping files below). Debug output is below that. What am I missing? I tried setting the "optimistic-lock" option at the class level for Empdep and Funddep to "none", but it doesn't change the behavior.

Any help you can provide would be very much appreciated. Thank you in advance.

Code:
<hibernate-mapping>
    <class name="com.faweb.entities.Compdep" table="COMPDEP">
        <id name="compdepid" type="long">
            <column name="COMPDEPID" />
            <generator class="identity" />
        </id>
        <version name="version" type="java.lang.Integer" unsaved-value="null">
            <column name="VERSION" />
        </version>
        <property name="submitted" type="true_false">
            <column name="SUBMITTED" length="1" not-null="false" />
        </property>
        <property name="lastUpdate" type="timestamp" insert="false" update="false" generated="always">
            <column name="LAST_UPDATE" length="26" />
        </property>
        <property name="dateVerified" type="timestamp">
            <column name="DATE_VERIFIED" length="26" />
        </property>
        <set name="empdeps" inverse="true" fetch="join" cascade="all">
            <key>
                <column name="COMPDEPID" not-null="true" />
            </key>
            <one-to-many class="com.faweb.entities.Empdep" />
        </set>
    </class>

--------------------------

    <class name="com.faweb.entities.Empdep" table="EMPDEP" optimistic-lock="none">
        <id name="empdepid" type="long">
            <column name="EMPDEPID" />
            <generator class="identity" />
        </id>
        <version name="version" type="java.lang.Integer" unsaved-value="null">
            <column name="VERSION" />
        </version>
        <many-to-one name="compdep" class="com.faweb.entities.Compdep" fetch="select">
            <column name="COMPDEPID" not-null="true" />
        </many-to-one>
        <property name="fiscaldate" type="int">
            <column name="FISCALDATE" not-null="true" />
        </property>       
        <property name="lastUpdate" type="timestamp" insert="false" update="false" generated="always">
            <column name="LAST_UPDATE" length="26" />
        </property>
        <map name="funddeps" inverse="true" fetch="join" lazy="true" cascade="all" optimistic-lock="false">
            <key column="EMPDEPID"/>
            <map-key column="FUNDNUM"
               type="int" />
            <one-to-many class="com.faweb.entities.Funddep" />
        </map>
    </class>


----------------------

    <class name="com.faweb.entities.Funddep" table="FUNDDEP" optimistic-lock="none">
        <id name="funddepid" type="long">
            <column name="FUNDDEPID" />
            <generator class="identity" />
        </id>
        <version name="version" type="java.lang.Integer" unsaved-value="null">
            <column name="VERSION" />
        </version>
        <many-to-one name="compdep" class="com.faweb.entities.Compdep" fetch="select">
            <column name="COMPDEPID" />
        </many-to-one>
         <many-to-one name="empdep" class="com.faweb.entities.Empdep" lazy="false" fetch="select">
            <column name="EMPDEPID" />
        </many-to-one>
        <property name="depamt" type="big_decimal">
            <column name="DEPAMT" precision="11" />
        </property>
        <property name="lastUpdate" type="timestamp">
            <column name="LAST_UPDATE" length="26" />
        </property>
    </class>



[b]Output:[/b]

Code:
[4/22/10 21:46:47:266 CDT] 00000033 SystemOut     O Hibernate:
    update
        faweb.COMPDEP
    set
        VERSION=?,
        SUBMITTED=?,
        DATE_VERIFIED=?
    where
        COMPDEPID=?
        and VERSION=?
[4/22/10 21:46:47:266 CDT] 00000033 SystemOut     O Hibernate:
    select
        compdep_.LAST_UPDATE as LAST29_97_
    from
        faweb.COMPDEP compdep_
    where
        compdep_.COMPDEPID=?
[4/22/10 21:46:47:281 CDT] 00000033 SystemOut     O Hibernate:
    update
        faweb.EMPDEP
    set
        VERSION=?,
        COMPDEPID=?,
        FISCALDATE=?,
    where
        EMPDEPID=?
[4/22/10 21:46:47:281 CDT] 00000033 SystemOut     O Hibernate:
    select
        empdep_.LAST_UPDATE as LAST19_108_
    from
        faweb.EMPDEP empdep_
    where
        empdep_.EMPDEPID=?
[4/22/10 21:46:47:281 CDT] 00000033 SystemOut     O Hibernate:
    update
        faweb.FUNDDEP
    set
        VERSION=?,
        COMPDEPID=?,
        EMPDEPID=?,
        DEPAMT=?,
        LAST_UPDATE=?
    where
        FUNDDEPID=?
[4/22/10 21:46:47:281 CDT] 00000033 SystemOut     O Hibernate:
    update
        faweb.FUNDDEP
    set
        VERSION=?,
        COMPDEPID=?,
        EMPDEPID=?,
        DEPAMT=?,
        LAST_UPDATE=?
    where
        FUNDDEPID=?


Top
 Profile  
 
 Post subject: Re: Preventing update to non-dirty children associations
PostPosted: Fri Apr 23, 2010 3:07 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
When you are calling session.update() you are telling Hibernate to update your objects, so it should not be surprising that everything is updated. Since the session has no knowledge of your entities (they are detached) Hibernate can't know if the are dirty or not. The trick to get the desired behavior is to let the session know about the entities before you make changes to them. The best way to do this is to use session.lock() (with LockMode.NONE). Note that this must be done BEFORE you make any changes to the entities. For example:

Code:
session.lock(compDep, LockMode.NONE);
// code here that updates the entities
session.flush();


Depending on your framework the above solution may be hard to implement. Another option is to use session.merge() instead of session.update(). The merge method will load the entities from the database, merge your changes and then update only those that have been modified. The drawback is that you will see SELECT:s for each entity instead of UPDATE.


Top
 Profile  
 
 Post subject: Re: Preventing update to non-dirty children associations
PostPosted: Fri Apr 23, 2010 10:58 am 
Beginner
Beginner

Joined: Sun Oct 14, 2007 7:29 pm
Posts: 23
Thank you Sweden! One more question -- what is it about session.lock() that may be hard to implement in my framework (i.e., what do I need to look out for)?

Thanks,

Matt


Top
 Profile  
 
 Post subject: Re: Preventing update to non-dirty children associations
PostPosted: Fri Apr 23, 2010 1:42 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
For example, if the user interaction spans multiple steps and you want to commit everything in one go after the last step. If you are using a session-per-request pattern you would need some temporary storage for changes made in the intermediate steps and then copy everything to the real objects in the last step. The key issue here is that session.lock() sets the "original" state. Hibernate can only detect changes that are made after this call.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.