Cannot save or update entity on Spring App

#1

I've got this DAO in my Spring App

import javax.transaction.Transactional;

@Repository // or @Component
@Transactional
public class LanguageRepository {
    // Injected database connection:
    @PersistenceContext private EntityManager em;

    // Stores a new guest:
    @Transactional
    public Language persist(Language guest) {
        em.persist(guest);
        em.flush();
        em.refresh(guest);
        return guest;
    }

    @Transactional
    public boolean update() {
        return em.createQuery("...").executeUpdate() > 0;
    }
}

While the fetching methods work, there are two huge problems: the persist method does not create a new entity, nor it refreshes with its new id. And the update method fails because of this:

[ObjectDB 2.8.0] javax.persistence.TransactionRequiredException Attempt to run update query when no transaction is active [PMImpl] (error 611)

Here's how I set up the transactionManager:

@Bean
    public JpaTransactionManager transactionManager() throws ClassNotFoundException {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getNativeEntityManagerFactory());
        transactionManager.afterPropertiesSet();
        return transactionManager;
    }
#2

Also, I've got this as a requirement:

@Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
        entityManagerFactoryBean.setJpaVendorAdapter(new AbstractJpaVendorAdapter() {
            
            @Override
            public PersistenceProvider getPersistenceProvider() {
                return new com.objectdb.jpa.Provider();
            }
             @Override
                public Map<String,?> getJpaPropertyMap() {
                 Map<String, String> map = new HashMap<>();
                 map.put(PROPERTY_NAME_JDBC_URL, environment.getRequiredProperty("objectdb.url"));
                 map.put(PROPERTY_NAME_JDBC_USER, environment.getRequiredProperty("objectdb.user"));
                    map.put(PROPERTY_NAME_JDBC_PASSWORD, environment.getRequiredProperty("objectdb.password"));
                    return Collections.synchronizedMap(map);
                }
        });
        
          
        Properties jpaProterties = new Properties();
        
        
        entityManagerFactoryBean.setJpaProperties(jpaProterties);

        return entityManagerFactoryBean;
    }
#3

> While the fetching methods work, there are two huge problems: the persist method does not create a new entity, nor it refreshes with its new id.

It is unclear from your posted code where the new entity object is instantiated but assuming that a new instance is passed to the method and not persisted, it may be related to your next reported issue:

> And the update method fails because of this: [ObjectDB 2.8.0] javax.persistence.TransactionRequiredException Attempt to run update query when no transaction is active [PMImpl] (error 611)

Apparently Spring Framework doesn't start a new transaction before the update method is invoked, even though that method is annotated as @Transactional. The cause of this is unclear.

Have you tried the Guestbook demo application of ObjectDB with Spring Framework (on this tutorial and the zip file that is attached to post #6 on this forum thread)?

ObjectDB Support
#4

I solved the problem by using an alternative to @Transactional annotation

 

@MappedSuperclass
@Component
public class DefaultRepository {
    // Injected database connection:
    @PersistenceUnit(unitName="pu") EntityManagerFactory entityManagerFactory;

    // Stores a new guest:
    public Object persist(Object guest) {
         EntityManager em = entityManagerFactory.createEntityManager();
        if (! em.getTransaction().isActive())
            em.getTransaction().begin();
        em.persist(guest);
        em.getTransaction().commit();
        
        em.flush();
        em.refresh(guest);
        em.clear();
        em.close();
        return guest;
    }
    //Updates existing entity
    public Object updateEntity(Object guest) {
        EntityManager em = entityManagerFactory.createEntityManager();
        if (! em.getTransaction().isActive())
            em.getTransaction().begin();
        em.merge(guest);
        em.getTransaction().commit();
        em.flush();
        em.clear();
        em.close();
        return guest;
    }
    //DELETE or UPDATE command
    public boolean deleteOrUpdate(String query, Map<String, Object> map) {
        EntityManager em = entityManagerFactory.createEntityManager();
        if (! em.getTransaction().isActive())
            em.getTransaction().begin();
        Query q = em.createQuery(query);
        for(String s : map.keySet())
            q.setParameter(s, map.get(s));
        boolean que = q.executeUpdate() > 0;
        em.getTransaction().commit();
        em.clear();
        em.close();
        return que;
    }
    
}

This is how I can call the methods:

@Component
public class LanguageRepository extends DefaultRepository{
    // Injected database connection:
    @PersistenceContext private EntityManager em;

    ...

    public Language save(Language guest) {
        if(guest.getId() == null)
            return (Language) persist(guest);
        return (Language) updateEntity(guest);
    }

    public boolean update() {
        Map<String, Object> map= new HashMap<String, Object>(); //Map for query parameters
        map.put("...", ...);
        return deleteOrUpdate("UPDATE Language l set ...", map);
    }
}

Reply