0

After executing the following operation in my Seam/Glassfish/JPA container:

@ApplicationScoped
public class JpaGlossaryDataAccessObject implements IGlossaryDataAccessObject {
    // ...
    @Transactional
    public void deleteColumn(String glossaryName, String columnName) {
        final GlossaryColumn column = getColumn(glossaryName, columnName);
        entityManager.remove(column);
    }
    // ...
}

the requested columns get successfully deleted from the DB, which I can verify using the SQL workbench. However, when calling the following method subsequently:

@ApplicationScoped
public class JpaGlossaryDataAccessObject implements IGlossaryDataAccessObject {
    // ...
    @Transactional
    public List<Glossary> getGlossaries(Collection<String> glossaryNames) {
        glossaryNames.retainAll(getGlossaryNames());
        return entityManager.createQuery(SELECT_ALL_NAMED_GLOSSARIES, Glossary.class).setParameter(GLOSSARY_NAMES_PARAMETER_INDEX, glossaryNames).getResultList();
    }
    // ...
}

which basically returns the Glossaries containing aforesaid columns, the deleted column is still in the Glossary object! Even though they don't exist anymore in the database. How can this be? Is there some additional refresh I need to perform in order to make this work?

My beans.xml looks like this, by the way:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="urn:java:ee"
    xmlns:security="urn:java:org.jboss.seam.security" xmlns:permission="urn:java:org.jboss.seam.security.permission"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
    <alternatives />
    <decorators />
    <interceptors>
        <class>org.jboss.seam.security.SecurityInterceptor</class>
        <class>org.jboss.seam.transaction.TransactionInterceptor</class>
    </interceptors>
    <security:IdentityImpl>
        <s:modifies />
        <security:authenticatorClass>ch.diction.webportal.security.seam.authentication.ChallengeResponseIdmAuthenticatorDecorator
        </security:authenticatorClass>
    </security:IdentityImpl>
</beans>

So, what am I missing?

Thanks in advance and best regards Pascal

Pascal Kesseli
  • 1,620
  • 1
  • 21
  • 37

2 Answers2

1

My first guess is you have cached data in memory inconsistent with the DB.

Make sure you clear the following 2 caches after doing bulk deletes. Any/all data in cache could be inconsistent with the DB:

  • the EntityManager cache (i.e. the persistence context): entityManager.clear();
  • the EntityManagerFactory cache (i.e. the level 2 cache):
    entityManager.getCache().evictAll();
    OR entityManagerFactory.getCache.evictAll();

It is theoretically (but not practically) possible to refresh every single object in the caches:

HashMap props = new HashMap();
// Semantically, refresh already bypasses the second level cache, no hint required. 
// But this hint says to then store the refreshed value back in the second level cache:
props.put("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
em.refresh(ent, props);

But that would be a real hassle and give no benefit. Firstly, how do you iterate through every entity stored in the cache(s)?? Secondly, if you just evict them with a singular call shown above, they are automatically reloaded in a refreshed state as needed.

It is even possible for you JDBC driver to be caching data. This would depend on your provider and configuration.

Any luck with this? =:-)

Glen Best
  • 22,769
  • 3
  • 58
  • 74
  • Thanks, that did help. I've had quite the mechanism set up to refresh all cached entities instead of just getting rid of the whole cache at once. The bottom line I take out of this is that, unless absolutely necessary, I don't retain my entity objects in the active persistence context for a sustained amount of time and instead let them become detached. – Pascal Kesseli Oct 26 '12 at 10:06
0

The scope of EntityManager is persistence context, you can use entityManager.clear().

clear() : Clear the persistence context, causing all managed entities to become detached

Else, you can close the EntityManager after processing & create a new one each time, which isn't overhead.

If it is being cached, you can try entityManager.getEntityManagerFactory().getCache().evictAll();

Nayan Wadekar
  • 11,444
  • 4
  • 50
  • 73