Results 1 to 2 of 2

Thread: EJB3 with Hibernate - merge operation not returning generated Ids

  1. #1

    Default EJB3 with Hibernate - merge operation not returning generated Ids

    Spring 1.2.7
    Hibernate version: Hibernate 3.2.0.cr2
    Hibernate Annotations 3.2.0.cr1

    This is an unusual problem we are having, and I would very much appreciate some help :-

    1) We have a situation where we seem to need to use hibernatetemplate merge() rather than saveOrUpdate() to persist a graph of of entities (Parent Entity with oneToMany assocation of child entities)

    - We send transfer objects back to our client tier.
    - When the modified TOs come back to the server tier they get translated as is into Hibernate Entity classes - effectively detached as this point (we can't change this architectural decision).
    - We use Spring hibernateDAOSupport to call merge() on the parent entity. The parent entity has a oneToMany association to a child entity e.g.

    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY )
    @JoinColumn(name = "circumstancesFk")
    @Cascade(org.hibernate.annotations.CascadeType.DEL ETE_ORPHAN)
    public List<ApplicantDO> getApplicants() {
    return applicants;
    }

    Previously our problem was that DELETE_ORPHAN that wasn't working until we used merge(). If we used a saveOrUpdate() hibernate did not detect that some orphans that had been removed from the child collection - updates and inserts all worked but NOT child deletes.

    Using merge() meant we could see that Hibernate would re-select the entity and then detect the deleted child orphans :-)
    (reading the hibernate docs I see the quote re: merge operation:- "if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance" )

    Hibernate now issues the delete (for the object that was deleted for the TO collection and therefore missing from the Entity Collection).


    2) Using merge() is now causing us a problem in that the operation that uses merge() must also provide functionality to INSERT the entity graph as well. If the TOs and Entities have a primary key of null the INSERT is correctly performed, however we have found that the merged Entity is not updated with its new primary key values or version.

    We have tried catching the returned object e.g.

    circumstances = (CircumstancesDO) getHibernateTemplate().merge(circumstances);

    however this doesn't seem to update the Id in the returned object.

    I notice that the docs for a merge() operation state
    "Note that merge will not update the identifiers in the passed-in object graph (in contrast to TopLink)! Consider registering Spring's IdTransferringMergeEventListener if you'd like to have newly assigned ids transferred to the original object graph too."

    So I tried using the IdTransferringMergeEventListener from latest Spring RC release (that is compatible with Hibernate 3.1), it gets invoke during the merge but get :-

    14:42:36,949 DEBUG [AbstractSaveEventListener] delaying identity-insert due to no transaction in progress

    in the IdTransferringMergeEventListener, then it finds that the id is null i.e.

    Serializable id = persister.getIdentifier(event.getResult(), session.getEntityMode());

    gets null id.


    We are using EJB3 Session Beans with Hibernate 3 Entities (via Hibernate Session not EJB3 entity manager) - so Transactions are demarcated in EJB3 SSB using annotation, I believe they are working ok, because the datasource is TX aware.

    So how is IdTransferringMergeEventListener supposed to work ? i.e. in situations where there is a transaction vs. no transaction ?

    Also do I need to do anything else to make Hibernate Session aware of the EJB3 container transaction? or is using TX aware datasource enough?

    I also tried tried configuring JtaTransactionManager (we're using JBoss), but I get the same result - in that the IdTransferringMergeEventListener still gets id of null and the message

    14:42:36,949 DEBUG [AbstractSaveEventListener] delaying identity-insert due to no transaction in progress

    still appears.

    Questions :-

    - Is there a better solution to the delete orphan issue with detached objects? I like having a single operation that copes with both inserts/updates/deletes but this seems difficult when using detached objects ?
    - How is IdTransferringMergeEventListener supposed to work ?

    Any help would be most appreciated.


    application context snipped :-

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTran sactionManager">
    <property name="userTransactionName"><null/></property>
    <property name="transactionManagerName">
    <value>java:/TransactionManager</value>
    </property>
    </bean>

    <bean id="hibernateSessionFactory"
    class="org.springframework.orm.hibernate3.annotati on.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="mformDS" />
    <property name="annotatedClasses" ref="annotatedClassesList">
    </property>
    <property name="hibernateProperties">
    <props>
    <prop key="hibernate.dialect">
    org.hibernate.dialect.MySQLDialect
    </prop>
    <prop key="hibernate.query.factory_class">
    org.hibernate.hql.classic.ClassicQueryTranslatorFa ctory
    </prop>
    <prop key="hibernate.show_sql">£{hibernate.show_sql}</prop>
    </props>
    </property>
    <property name="eventListeners">
    <map>
    <entry>
    <key>
    <value>pre-update</value>
    </key>
    <ref bean="validatePreUpdateEventListener"/>
    </entry>
    <entry>
    <key>
    <value>pre-insert</value>
    </key>
    <ref bean="validatePreInsertEventListener"/>
    </entry>
    <entry key="merge">
    <bean class="com.rdf.infra.spring.hibernate3.support.IdT ransferringMergeEventListener"/>
    </entry>
    </map>
    </property>
    </bean>

    EJB3 transaction annotations :-

    import javax.ejb.TransactionAttribute;

    @TransactionAttribute(TransactionAttributeType.REQ UIRED)
    public SearchCriteriaDTO saveSearchCriteria(String userId, SearchCriteriaDTO searchCriteria) {
    return getDelegateBean().saveSearchCriteria(userId, searchCriteria);
    }

    thanks for your time.

    In the log I can see the JTA mgr :-

    16:47:54,060 INFO [JtaTransactionManager] Using JTA UserTransaction: org.springframework.transaction.jta.UserTransactio nAdapter@735a55
    16:47:54,060 INFO [JtaTransactionManager] Using JTA TransactionManager: org.jboss.tm.TxManager@12faeca
    16:47:54,278 INFO [Version] Hibernate Annotations 3.2.0.CR1
    16:47:54,310 INFO [Environment] Hibernate 3.2 cr2
    16:47:54,310 INFO [Environment] loaded properties from resource hibernate.properties: {hibernate.bytecode.use_reflection_optimizer=false }

    but then get :-

    16:48:14,763 DEBUG [AbstractSaveEventListener] delaying identity-insert due to no transaction in progress

    16:48:24,716 DEBUG [AbstractFlushingEventListener] processing flush-time cascades
    16:48:24,716 DEBUG [AbstractFlushingEventListener] dirty checking collections
    16:48:24,716 DEBUG [AbstractFlushingEventListener] Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
    16:48:24,716 DEBUG [AbstractFlushingEventListener] Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
    16:48:24,716 DEBUG [Printer] listing entities:
    16:48:24,731 DEBUG [Printer] com.rdf.mform.domain.user.ExistingMortgageDetailsD O{monthlyPayment=component[currency,amount]{amount=49900, currency=GBP}, propertyLocation=England, loanAmount=component[currency,amount]{amount=50000000, currency=GBP}, loanAmountInterestPart=component[currency,amount]{amount=0, currency=GBP}, repaymentType=Repayment, dealType=DiscountedVariable, latestVersion=0, id=null, loanAmountRepaymentPart=null, loanTermYears=10}
    16:48:24,731 DEBUG [AbstractBatcher] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
    16:48:24,731 DEBUG [ConnectionManager] opening JDBC connection
    16:48:24,731 DEBUG [SQL] insert into existing_mortgage_details (latestVersion, repaymentType, loanAmountCur, loanAmount, loanTermYears, propertyLocation, loanAmountRepaymentPartCur, loanAmountRepaymentPart, loanAmountInterestPartCur, loanAmountInterestPart, dealType, monthlyPaymentCur, monthlyPayment) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    16:48:24,731 INFO [STDOUT] Hibernate: insert into existing_mortgage_details (latestVersion, repaymentType, loanAmountCur, loanAmount, loanTermYears, propertyLocation, loanAmountRepaymentPartCur, loanAmountRepaymentPart, loanAmountInterestPartCur, loanAmountInterestPart, dealType, monthlyPaymentCur, monthlyPayment) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    16:48:24,747 DEBUG [IdentifierGeneratorFactory] Natively generated identity: 1002
    16:48:24,747 DEBUG [AbstractBatcher] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
    16:48:24,747 DEBUG [ConnectionManager] releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
    16:48:24,762 DEBUG [ConnectionManager] transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!

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

    Default

    Can you try with using Hibernate 3.1.3 and Hibernate annotations 3.1.0 beta 10 (if 3.2.0 CR1 is not working)?
    If you still have issues, please raise an issue on JIRA- thanks.
    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

Posting Permissions

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