0

I use JPA + Hibernate + Spring for simple job. I wrote next modules:

Service:

@Autowired
private VolMng volMng;

@Service
public class Dist {

@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void gen() {
        MeterLog mLog = em.find(MeterLog.class, 3625190);
        Lst volTp = lstMng.findByCD("Fact Vol");
        Vol vol = new Vol((MeterLog) mLog, volTp, 7777.77d);
        volMng.add(vol);
        //point-1:
        for (Vol a : mLog.getVol()) {
            System.out.println("found="+a.getId()+" vol="+a.getVol1());
        }
...
...

Service:

@Service
public class VolMngImpl implements VolMng {

    @Autowired
    private VolDAO vDao;

    public void add(Vol vol) {
        vDao.add(vol);
    }

}

DAO:

@Repository
public class VolDAOImpl implements VolDAO {

    @PersistenceContext
    private EntityManager em;

    public void add(Vol vol) {
        em.persist(vol);
    }

}

I am trying to add some records to child entity Vol.

But after volMng.add(vol) at point-1 I don't see any added records (child entities). Why?

upd

Of course I see these records after end of transaction, but why I can't do it before??? They must be in memory cache...

upd2

My spring.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd">

    <!-- *******************************
         ***** CACHE CONFIGURATION ***** 
         ******************************* -->                
    <cache:annotation-driven  cache-manager="cacheManager" />

    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="ehcache"/>
    </bean>
    <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache.xml"/>
        <property name="shared" value="true"/>
    </bean>    

    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close"> 
          <property name="URL" value="jdbc:oracle:thin:@192.168.1.1:1521:DEV" /> 
          <property name="user" value="ora"/> 
          <property name="password" value="ora"/> 
          <property name="connectionCachingEnabled" value="true"/> 
    </bean>

    <bean
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        id="entityManagerFactory">
        <property name="dataSource" ref="dataSource" />
    </bean>

     <context:component-scan base-package="com.ric.bill" />
     <context:component-scan base-package="com.ric.bill.dao.impl" />
     <context:component-scan base-package="com.ric.bill.mm.impl" />


    <bean class="org.springframework.orm.jpa.JpaTransactionManager"
        id="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

 <tx:annotation-driven mode="proxy" transaction-manager="transactionManager"/>



    <context:spring-configured />
    <context:annotation-config />


</beans>
sleeplessnerd
  • 21,853
  • 1
  • 25
  • 29
Leo
  • 1,029
  • 4
  • 19
  • 40

3 Answers3

1

Collections are not automatically updated in the session. It will appear once you reload everything, but you have to manually add it to the children collection of the owning object in case you need it in the current session.

sleeplessnerd
  • 21,853
  • 1
  • 25
  • 29
0

To solve this problem I have to add children entity to the parent, like this:

    MeterLog mLog = em.find(MeterLog.class, 3625190);
    Lst volTp = lstMng.findByCD("Fact Vol");
    Vol vol = new Vol((MeterLog) mLog, volTp, 7777.77d);
    mLog.getVol().add(vol);
    //point-1:
    for (Vol a : mLog.getVol()) {
        System.out.println("found="+a.getId()+" vol="+a.getVol1());
    }
Leo
  • 1,029
  • 4
  • 19
  • 40
0

To answer the actual question -- why can't you see the newly added entity...

You run a select statement and put the results in a java object:

MeterLog mLog = em.find(MeterLog.class, 3625190);

The find ultimately creates the select statement and the result set is transformed into the MeterLog object via hibernate according to the jpa annotations you've used to define the mapping. From this point on your code doesn't change this object. You create a new entity with this code:

volMng.add(vol);

which directly persists the new entity in the database. But, this is after the select has already returned the data you asked for. You don't do anything to change or refresh the result set you've already acquired. The underlying datastore (oracle, mysql, whatever) doesn't remember that you've queried it and are holding a copy of its data, so it can do nothing to alert you to the fact that the underlying data has changed.

As you mention in your answer, you can add the new entity directly to the object's collection:

mLog.getVol().add(vol);

And this will, in certain circumstances, persist the new entity to the database when the transaction successfully completes, but also allows you to see the entity when you're looping through the collection, hence your observation. You have broken the law of Demeter by doing this here however -- it should be Vol's responsibility to add itself to the collection of volumes of the given MeterLog when it is created.

Software Engineer
  • 15,457
  • 7
  • 74
  • 102