Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA disable auto save

i use JPA eclipse Toplink & EJB

everytime i receive entity from database then change some data inside of it,

database(MYSQL) automaticly change too without i commit or do something

Example:

Player p = em.findById(1);
p.setName(newName);
// i do nothing , but database automaticly change

i already read related question here, but i still can't figure it out

i think i must detach entity but i don't know how to do this, because

i have class GenericDAO generated from netbeans

GenericDAO (generated from netbeans)

public abstract class GenericDAO<T> {
    private Class<T> entityClass;

    public GenericDAO(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void insert(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void delete(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T findById(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List<T> findRange(int[] range) {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0] + 1);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

}

DaoPlayer

@Local
public interface DaoPlayer{
    void insert(Player player);

    void edit(Player player);

    void delete(Player player);

    Player findById(Object id);

    List<Player> findAll();

    List<Player> findRange(int[] range);

    int count();

ImplPlayer

@Stateless
public class ImplPlayer extends GenericDAO<Player> implements DaoPlayer{
    @PersistenceContext(unitName = "MonsterPuzzle")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public ImplPlayer() {
        super(Player.class);
    }

}

My question is

  • how to disable JPA automaticly save to database?
  • ( Because i think i need to detach )how to detach the entity from GenericDAO?
like image 519
Rollin x Avatar asked Sep 23 '14 00:09

Rollin x


Video Answer


2 Answers

You will need to look into how you are managing transactions in your application. Consider one of your methods:

Player findById(Object id){}

If you are using Container Managed Transactions in a Java EE environment, you just need to mark the transaction as not supported in the DAO.

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
Player findById(Object id) {}

This will make sure that the transaction is not open when the Dao passed the entity back to a different layer. Any changes you make to the entity will not be synchronized with the database.

like image 176
SJha Avatar answered Sep 20 '22 00:09

SJha


Understand this: "every update in an attached entity will be reflected in the database".

When an entity is attached? To put it in a simple way, every entity that pass through the EntityManager with the methods: persist, merge, refresh, delete (maybe I am forgetting some any other here) or in the query (JPQL or find) methods inside a transaction.

Look at the sample below:

entityManager.getTransaction().begin();
Dog dog = entityManager.find(Dog.class, 1);
dog.setGoodBoyLevel(99);
entityManager.getTransaction().commit();

Since dog passed by the find method inside a transaction it can be considered managed.

If you are using EJB you must know that the default transaction is REQUIRED. The REQUIRED works like: If there is a transaction opened, let us use it. If there is no transaction opened, let us open it. (It is a nice guy)

Since your method is without any indicator to suspend the transaction every update in the entity will be reflected in the database. What could you do? Use the NOT_SUPPORTED transaction way:

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void yourMethod(){
    // to awesome things
}

Since you are using the NOT_SUPPORTED transaction option your entity will be detached. What does detached means? The JPA will not analyse the updates in the entity. If you want just read some info, that is ok. But the code below will raise exception:

entityManager.getTransaction().begin();
Dog dog = new Dog();
Owner owner = getDetachedOwner(ownerId);
dog.setOwner(owner);
entityManager.persist(dog);
entityManager.getTransaction().commit();

The problem here is that the owner is detached, so the JPA do not knows it and would raise an exception.

Be careful with the NOT_SUPPORTED option. [=

like image 22
uaiHebert Avatar answered Sep 21 '22 00:09

uaiHebert