Results 1 to 9 of 9

Thread: Help with persistance of multiple objects of the same type in a single transaction

  1. #1
    Join Date
    Jan 2006
    Posts
    5

    Default Help with persistance of multiple objects of the same type in a single transaction

    Hello,

    I am developing a web app where I have two different object references to an object of the same type.

    Ex:

    Code:
    Class Building{
        private Person admin;
        private Person contact;
    }
    The hibernate mapping of this object is of the form:

    HTML Code:
    <hibernate-mapping>
    	<class name="com.cma.model.inmuebles.Building" table="buildings">
    		<id name="buildingId" type="integer">
    			<column name="buildingID" />
    			<generator class="identity" />
    		</id>
    
    		some properties here ....
    
    		<many-to-one name="admin" class="com.cma.model.Person" cascade="save-update" lazy="false">
    			<column name="adminID" />
    		</many-to-one>
    
    		<many-to-one name="contact" class="com.cma.model.Person" cascade="save-update" lazy="false">
    			<column name="contactID" />
    		</many-to-one>
    </hibernate-mapping>
    We are using Spring with Hibernate and dao support with the default hibernate filter OpenInSessionInViewFilter (Single Session mode). In the jsp form I have binded correctly both references. However when I submit the form with a different admin or contact hibernate is not able to update the current person with the new one, and I get a this type of exception: org.hibernate.HibernateException: identifier of an instance of com.cma.model.Person altered from 359 to 61

    This is the stack trace of the exception:

    Handler execution resulted in exception - forwarding to resolved error view
    org.springframework.orm.hibernate3.HibernateSystem Exception: identifier of an in stance of com.cma.model.Persona altered from 358 to 273; nested exception is org.hibernate.HibernateException: identifier of an instance of com.cma.model.Person a altered from 358 to 273 org.hibernate.HibernateException: identifier of an instance of com.cma.model.Persona altered from 358 to 273
    at org.hibernate.event.def.DefaultFlushEntityEventLis tener.checkId(DefaultFlushEntityEventListener.java :51)
    at org.hibernate.event.def.DefaultFlushEntityEventLis tener.onFlushEntity
    (DefaultFlushEntityEventListener.java:82)
    at org.hibernate.event.def.AbstractFlushingEventListe ner.flushEntities(AbstractFlushingEventListener.ja va:190)
    at org.hibernate.event.def.AbstractFlushingEventListe ner.flushEverythingToExecutions(AbstractFlushingEv entListener.java:70)
    at org.hibernate.event.def.DefaultFlushEventListener. onFlush(DefaultFlushEventListener.java:26)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.j ava:730)
    at org.hibernate.impl.SessionImpl.managedFlush(Sessio nImpl.java:324)
    at org.hibernate.transaction.JDBCTransaction.commit(J DBCTransaction.java:86)
    at org.springframework.orm.hibernate3.HibernateTransa ctionManager.doCommit(HibernateTransactionManager. java:490)
    at org.springframework.transaction.support.AbstractPl atformTransactionManager.processCommit(AbstractPla tformTransactionManager.java:495)
    at org.springframework.transaction.support.AbstractPl atformTransactionManager.commit(AbstractPlatformTr ansactionManager.java:468)
    at org.springframework.transaction.interceptor.Transa ctionAspectSupport.doCommitTransactionAfterReturni ng(TransactionAspectSupport.java:258)
    at org.springframework.transaction.interceptor.Transa ctionInterceptor.invoke(TransactionInterceptor.jav a:106)
    at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :144)
    at org.springframework.aop.framework.JdkDynamicAopPro xy.invoke(JdkDynamicAopProxy.java:174)
    at $Proxy6.saveCaptacion(Unknown Source)
    at com.cma.webapp.action.CaptacionFormController.onSu bmit(CaptacionFormController.java:198)
    at org.springframework.web.servlet.mvc.SimpleFormCont roller.processFormSubmission(SimpleFormController. java:258)

    I tried implenting this situation in deferred close mode and it works for this case, however there are other parts of the application, where it fails to keep persistent objects associated with a specific session.

    The transactions of the application are defined as follows:

    HTML Code:
    <bean id="txProxyTemplate" abstract="true"
            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <property name="transactionManager" ref="transactionManager"/>
            <property name="transactionAttributes">
                <props>
                    <prop key="save*">PROPAGATION_REQUIRED</prop>
                    <prop key="remove*">PROPAGATION_REQUIRED</prop>
                    <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
                </props>
            </property>
        </bean>
    I am fairly new to Spring and Hibernate, and I am not understanding why hibernate is not able to update these references.

    Any suggestion on how to solve this will be appreciated!

  2. #2
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    I recommend to take a look at your infrastructure and see how Hibernate works. The problem is that you are editing the id of an object which is attached to the opened session (the one opened by OpenSessionInView (OSIV)) and already saved.
    HB can do updates to objects except for their id (a new id means a new object) - review or code and save the new object instead of updating the old one.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  3. #3
    Join Date
    Jan 2006
    Posts
    5

    Default

    Thanks Costin. I'm not actually trying to change the object's ID, I'm trying to reference a totally different object of the same type.

    My person table has two people:

    id = 1 name = Joe
    id = 2 name = Peter

    My Building object initially references the Joe Person object, like this at the database level:

    buildings table:

    buildingID = 1 contactID = 23 adminID = 1 (FK to person table id)

    All I need is to change this record to adminID = 2

    In Java code, I start by loading Building 1, and Hibernate also correctly loads a reference to the Person object Joe (id = 1).

    To change the administrator, all I imagine I need to do is to call:

    building.setAdminPerson(peter).

    The peter object has also been loaded from the database by Hibernate.

    then I call:

    getHibernateTemplate().saveOrUpdate(building), getting the
    org.hibernate.HibernateException: identifier of an instance of com.cma.model.Person altered from 1 to 2

    I also tried to call building.setAdminPerson(null) with the same results !

    Shouldn't this work ??
    How do I change and persist references to other persitent objects ?

  4. #4
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    You are using cascade functionality - in this case saving the building object will update the old object which means updating the joe object with the details of peter.
    See the HB documentation which explains in details the semantics of save-update, cascading and removing and updating associations.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  5. #5
    Join Date
    Jan 2006
    Posts
    5

    Default Solved!

    Thanks again Costin for your reply,

    The problem was how the objects were binded in the jsp. The solution was to bind all the properties of the object within a single bind, and use a property editor to instantiate a different Object Person.

    Ex:

    Code:
    public class Person{
    
    int id;
    String names;
    String lastNames;   
    }
    I was binding each property separete in the jsp like this:

    Code:
    <spring:bind path="building.admin.id">
                    <input type="hidden" name="<c:out value="${status.expression}"/>" id="personId" value="<c:out value="${status.value}"/>"
                         />	         
                </spring:bind>
    
    
    <spring:bind path="building.admin.name">
                    <input type="hidden" name="<c:out value="${status.expression}"/>" id="personName" value="<c:out value="${status.value}"/>"
                         />	         
                </spring:bind>
    Now we have,

    Code:
    <spring:bind path="building.admin">
    the person's properties are exposed through <c:out value="${building.person.id}"/>
    </spring:bind>
    Cheers,

  6. #6
    Join Date
    Sep 2005
    Location
    Newcastle, Australia
    Posts
    61

    Thumbs up

    Thanks for posting your solution. I was struggling with this problem myself until I stumbled upon this thread.

  7. #7
    Join Date
    Dec 2006
    Posts
    10

    Default Property Editor to Instantiate different Object

    I am having the same problem... You stated that you used property editor to instantiate a different Object Person. Can you tell me how you did this or show me code that would do this?

    Thanks,
    Tim

  8. #8
    Join Date
    Sep 2005
    Location
    Newcastle, Australia
    Posts
    61

    Default

    When binding to a domain object as a whole, rather than by individual properties within the domain object, you need to tell Spring how to to do the binding, since Spring is actually binding directly to a domain object, and not to a String or Integer or other simple class.

    so in the example below...
    Code:
    <spring:bind path="building.admin">
    the person's properties are exposed through <c:out value="${building.person.id}"/>
    </spring:bind>
    you might add the following code in your controller's initBinder() method

    Code:
    binder.registerCustomEditor(Person.class,new PersonEditor());
    your PersonEditor class might look something like...

    Code:
    public class PersonEditor extends PropertyEditorSupport {
    
    	public void setAsText(String text) throws IllegalArgumentException {
    		Personobj = null;
    		if (text == null || text.length() == 0) {
    			setValue(null);
    		} else {
    			obj = new Person();
    			obj.setId(Integer.parseInt(text));
    			setValue(obj);
    		}
    	}
    
    	public String getAsText() {
    		Personvalue = (Person) getValue();
    		if (value != null) {
    			return value.getId().toString();
    		} else {
    			return "";
    		}
    	}
    }

  9. #9
    Join Date
    Dec 2006
    Posts
    10

    Default Thank you

    Thank you soooo much! I still don't entirely grasp how it works, but I used your code and it solved my super annoying problem... I can't believe there isn't more talk about this subject. Anyways, I couldn't have done it with out you and I owe you big time!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •