Announcement Announcement Module
Collapse
No announcement yet.
Hibernate cascading disabled for @Transactional junit tests ? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hibernate cascading disabled for @Transactional junit tests ?

    I've got the weird problem that with @Transactional annotated test cases the persisting event cascading does not work. It works when the annotation is removed.

    There's a three-level JPA entity class structure. Say A, B and C. Class A references an instance of class B with @OneToMany(cascade = CascadeType.ALL). And so does class B reference an instance of class C.

    In order to check class C's changes gets persisted I've added a logging method into class C

    Code:
    @PrePersist
    @PreUpdate
    private void reportSave() {
      System.out.println("Persisting " + this);
    }
    The test consists in modifying a number of instances of class C. After that class A gets persisted with jpaTemplate.merge(A).

    When the test is not annotated with @Transactional, the logging method is called. And indeed, the database contains the modifications. However, when the test is annotated with @Transactional, the logging method is not called. And unfortunately the changes were not committed either. Logically, performing cascading is not related the presence of a transaction. Or is it ?


    Is there somebody in here who knows what the obvious thing is I'm missing ? It's probably just a detail, but I can't find it. Just to make sure, I've updated to the very latest versions of the libraries. I'm adding the system configuration underneath.

    Any clue is welcome. :-) MANY thanks !!!

    =====================================

    A typical test case configuration:

    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("/test-beans.xml")
    @TransactionConfiguration
    @Transactional
    public class MyUnitTest {
    
    ...
    
      @Test
      public void testSomething() {}  
    
    ...
    
    }
    An extract of the Spring xml configuration file - nothing fancy there I think ...

    Code:
      <context:annotation-config />
    
      <tx:annotation-driven transaction-manager="transactionManager" />
    
      <context:component-scan base-package="com.foo.bar"  />
    
      <bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
      </bean>
    
      <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceXmlLocation" value="/META-INF/persistence.xml"/>
        <property name="persistenceUnitName" value="bar" />
      </bean>
      
      <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
      </bean>
    Extract from persistence.xml

    Code:
    <persistence-unit name="bar" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
          <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
          <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/bar" />
          <property name="hibernate.connection.username" value="bar" />
          <property name="hibernate.connection.password" value="pwd" />
          <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
          <property name="hibernate.hbm2ddl.auto" value="create"/>
          <property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
        </properties>
      </persistence-unit>
    Libraries
    • Spring 3.0.6 ORM/CONTEXT/TEST
    • Hibernate 3.6.7.Final
    • JUnit 4.9
    • JPA2

  • #2
    Found it ! An improper entity manager usage was turning bad when transactions were enabled. It wasn't related to the persistence but was done right before it. Causing the persistence to fail in some way.

    I implemented a Query result iterator for which an EntityManager was required. I thought I could create it from the EntityManagerFactory of the jpaTemplate.

    Code:
        final EntityManager em = jpaTemplate.getEntityManagerFactory().createEntityManager();
        return new QueryIterator<T>(em.createQuery("FROM Foo"));
    Obviously not. It seems the EntityManager has to be obtained in a different way. As described underneath.

    Code:
        jpaTemplate.execute(new JpaCallback() {
          @Override
          public Object doInJpa(final EntityManager em) throws PersistenceException {
            return new QueryIterator<T>(em.createQuery("FROM Foo"));
          }
        });
    Now it all works ok. As it is supposed to be, regardless of transactions being present or not. :-)

    Comment

    Working...
    X