Why does not my managerbean delete entities when sending my entity?

1

For some reason when trying to delete an entity with

public void remove(Notification notification){
    try {
        em.merge(notification);
        em.remove(notification);
    } catch (Exception e) {
        System.out.println("No se pudo remover la notificación "+e.getMessage());
    }
}

send me this error

Entity must be managed to call remove: 4, try merging the detached and try the remove again.

but with when using:

public void remove(Notification notification){
    try {


        em.merge(em.find(Notification.class, notification.getId()));
        em.remove(em.find(Notification.class, notification.getId()));
    } catch (Exception e) {
        System.out.println("No se pudo remover la notificación "+e.getMessage());
    }
}

I would like to know why this happens, as I understand that

(em.find(Notification.class, notification.getId())

should return the same entity that I send with

em.remove(notification);

I just do not find sense. I hope you help me understand. why it happens.

    
asked by gibran alexis moreno zuñiga 06.01.2017 в 20:41
source

2 answers

1

The EntityManager#merge method returns an instance associated with the context, it will not modify the instance that you send as a parameter. For your code to work, it should be like this:

Notification mergedNotification = em.merge(notificacion);
//luego de la línea anterior:
//notification sigue siendo el mismo objeto del parámetro sin modificaciones
//mergedNotification es una nueva instancia de la clase Notification
//que está asociada al contexto de JPA (nivel 1 de caché, para ser precisos)
//ahora lo puedes remover
em.remove(mergedNotification);

The advantage of this method is that it is useful when you want to do a cascading elimination of objects. But beware, be careful with the performance of the application in this case. Consider that when you use EntityManager#merge you must register the object in the database by INSERT or UPDATE and perform other additional operations (eg reflection) which affects the performance of the application, especially if the object is very heavy eg. if you have a blob field that has an image or a file. If it is a single entity basically unrelated or if you want to perform a massive operation (better known by its term in English bulk operation ), the best in terms of performance would be to use the Criteria API with a code as follows:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaDelete<Notification> query = cb.createCriteriaDelete(Notification.class);
Root<Notification> root = query.from(Notification.class);
query.where(cb.equal(root.get("id"), notification.getId()));

int result = entityManager.createQuery(query).executeUpdate();

You could also achieve it with JPQL but the Criteria API has the advantage that you can receive the class as a parameter, which makes it easier to create a more generic method to generalize the code above, for example:

interface Entidad<T> {
    T getId();
    void setId(T id);
}

public class Notification implements Entidad<Integer> {
    /* definición de la clase */
    Integer id;
    //getter y setter..
}

class DaoGenerico {
    EntityManager em;
    public DaoGenerico(EntityManager em) {
        this.em = em;
    }
    public <E extends Entidad<?>> void borraMedianteApiCriteria(Class<E> claseEntidad, E entidad) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaDelete<E> query = cb.createCriteriaDelete(claseEntidad);
        Root<E> root = query.from(claseEntidad);
        query.where(cb.equal(root.get("id"), entidad.getId());
        em.createQuery(query).executeUpdate();
    }
}
    
answered by 06.01.2017 / 21:05
source
0

In hibernate entities can be in any of these states .

  • New (transient): an entity is new if it has just been instantiated using the new operator, and it is not associated with a persistence context. It has not persisted representation in the database and no identifier value has been assigned.

  • Managed (persistent): a managed entity instance is an instance with a persistent identity that is currently associated with a persistence context.

  • Detached: the entity instance is an instance with a persistent identity that is not associated with a persistence context, usually because the persistence context was closed or the instance was evicted from the context.

  • Removed: a removed entity instance is an instance with a persistent identity, associated with a persistence context, but scheduled for removal from the database.

Hibernate can only work with Managed entities in order to manipulate their state and transfer those actions to the base through SQL, otherwise it will not allow you, therefore a Detached entity that is outside the persistent context can not be persisted or modified in the base, for this you must return your entity back to the persist context and convert your entity Detached to Managed.

In your case the entity 'book' that arrives as parameter the method has been disassociated from the persistence context therefore it is not being managed (detached) by it, that is the reason why it does not allow you to delete it.

When doing

em.find(Notification.class, notification.getId())

You are making a new query to the database by obtaining a new entity, in this case if it is inside the persistence context and for that reason it allows you to delete it.

when doing

em.merge(libro); // libro pasa al persistence context y se convierte en un managed entity
em.remove(libro);

You are adding the detached entity (book) 'book' to the persistence context using the .merge () method, therefore this entity Disassociated (Detached) now becomes managed (Managed), for that reason you can now delete.

Now in your next example, this snippet of code.

em.merge(em.find(Notification.class, notification.getId()));
em.remove(em.find(Notification.class, notification.getId()));

you can simplify it as

Notificacion notificacion = em.find(Notification.class, notification.getId());
em.remove(notificacion);

However this to SQL translates to the following.

SELECT * FROM notificacion WHERE id = :id
DELETE FROM notificacion WHERE id = :id

The first select is necessary in hibernate since this way you get the managed entity (Managed) to be able to eliminate it later with em.remove, but if you only need the ID to be able to delete an entity in SQL then technically the first select is a waste.

Another way to eliminate a disassociated entity is like this.

Libro entity = getEntityManager().getReference(Libro.class, libro.getId());
getEntityManager().remove(entity);

In this case, getReference creates a proxy entity and does not load the status (data) of the database book. (You can only call the set methods of this proxy object).

This is much better since by not loading the database data this only makes the delete and not the first select .

DELETE FROM libro WHERE id = :id
    
answered by 06.01.2017 в 21:47