Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA/Hibernate remove entity not working

I'm using a JPA interface to Hibernate, and I've written some simple code to load an entity from the database and then remove (delete) it. All of my merge calls to insert and update entities are working perfectly, but when I try to remove an entity, Hibernate doesn't delete it from the database, and no exception is thrown. I've included the relevant code below:

Primary method:

/**
 * Accept an invite that was sent to you.
 * 
 * @param inviteId
 * @return XML model of the EventMember.
 */
@RequestMapping(value="/invites/accept.rest")
public ModelAndView acceptInvite(@RequestParam final long inviteId) {
    final EventInvite invite = eventInviteDAO.find(EventInvite.class, eventInviteId);

    EventMember eventMember = new EventMember();
    eventMember.setEvent(invite.getEvent());
    eventMember.setUser(invite.getUser());
    eventMember = eventMemberDAO.store(eventMember);

    eventInviteDAO.remove(invite);

    return getXMLModelAndView("eventMember", eventMember);
}

AbstractJpaDao class (inherited by all DAO classes):

public abstract class AbstractJpaDao<T> implements JpaDao<T> {
    abstract public EntityManager getEntityManager();

    public <T> T find(Class<T> entityClass, Object primaryKey) {
        return getEntityManager().find(entityClass, primaryKey);
    }

    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    public T store(final T objectToPersist) {
        T result = getEntityManager().merge(objectToPersist);
        return result;
    }

    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    public void remove(final T objectToDelete) {
        getEntityManager().remove(objectToDelete);
    }
}

EventInvite domain class:

@Entity
@Table(name = "TEventInvite")
public class EventInvite implements Serializable {
    private static final long serialVersionUID = 1L;

    @Column(name = "EventInviteID", nullable = false)
    @Basic(fetch = FetchType.EAGER)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long eventInviteId;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumns( { @JoinColumn(name = "EventID", referencedColumnName = "EventID", nullable = false) })
    private Event event;

    @Column(name = "Email")
    @Basic(fetch = FetchType.EAGER)
    private String email;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "CreateDate", nullable = false)
    @Basic(fetch = FetchType.EAGER)
    private Calendar createDate;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumns( { @JoinColumn(name = "UserID", referencedColumnName = "UserID") })
    private User user;

    public void setEventInviteId(long eventInviteId) {
        this.eventInviteId = eventInviteId;
    }

    public long getEventInviteId() {
        return this.eventInviteId;
    }

    public Event getEvent() {
        return event;
    }

    public void setEvent(Event event) {
        this.event = event;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getEmail() {
        return this.email;
    }

    public void setCreateDate(Calendar createDate) {
        this.createDate = createDate;
    }

    public Calendar getCreateDate() {
        return this.createDate;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((createDate == null) ? 0 : createDate.hashCode());
        result = prime * result + ((email == null) ? 0 : email.hashCode());
        result = prime * result + ((event == null) ? 0 : event.hashCode());
        result = prime * result + ((user == null) ? 0 : user.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        EventInvite other = (EventInvite) obj;
        if (createDate == null) {
            if (other.createDate != null)
                return false;
        } else if (!createDate.equals(other.createDate))
            return false;
        if (email == null) {
            if (other.email != null)
                return false;
        } else if (!email.equals(other.email))
            return false;
        if (event == null) {
            if (other.event != null)
                return false;
        } else if (!event.equals(other.event))
            return false;
        if (user == null) {
            if (other.user != null)
                return false;
        } else if (!user.equals(other.user))
            return false;
        return true;
    }

}

Any ideas about what the problem might be or how to debug it?

like image 935
Templar Avatar asked Feb 05 '11 20:02

Templar


3 Answers

Is it getting confused because the EventInvite crosses transaction boundaries? You load the entity in one transaction and delete it in another.

Instead, create a new @Transactional method that contains the complete business logic for accepting an invite as it is a single logical operation. Doing so will also separate the presentation layer from the model for when you want to enable accepting invitations via SMS or email.

like image 142
David Harkness Avatar answered Oct 19 '22 02:10

David Harkness


I had a similar problem, I had a class which describes a value which is a part of a category. So the value class has a reference to the category that it is a part of.

@Entity
public class CategoryValue extends LouhinObject implements Serializable, Idable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne
    private Category category;
}

I had to manually set the category field to null before I was able to remove the CategoryValue object, I don't really know why Hibernate works this way.

like image 44
user344146 Avatar answered Oct 19 '22 02:10

user344146


I had the same problem. My entity is Card (see below). And I couldn't set null to an account and a client, because I have not-null checks in database.

public class Card implements Serializable {  
    @ManyToOne 
    @JoinColumn(name="idAcc")
    private Account account; 
    @ManyToOne 
    @JoinColumn(name="idCl")
    private Client client;

And when I tryed to delete it I even didn't see sql-request about deleting.

    em = getEntityManager();
    em.getTransaction().begin();  
    mergedCard = em.merge(card); 
    em.remove(mergedCard); 
    em.getTransaction().commit();

So I resolved this by annotations

 @ManyToOne(cascade=CascadeType.MERGE)
@JoinColumn(name="idAcc")
private Account account; 
@ManyToOne(cascade=CascadeType.MERGE)
@JoinColumn(name="idCl")
private Client client;
like image 29
Foontik Avatar answered Oct 19 '22 02:10

Foontik