Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA many to many merge on the owner triggers delete on join table

I have many to many relation between Customer and BusinessUnit:

public class Customer extends AbstractEntity {

    @JoinTable(name = "CUS_BUS_UNITS", 
            joinColumns = {
                @JoinColumn(name = "CUS_ID", referencedColumnName = "CUS_ID")},
            inverseJoinColumns = {
                @JoinColumn(name = "BUS_ID", referencedColumnName = "BUS_ID")})
    @ManyToMany
    private Collection<BusinessUnit> businessUnits;
}

public class BusinessUnit extends AbstractEntity {

    @ManyToMany(mappedBy = "businessUnits")
    private Collection<Customer> customers;

}

When i call entityManager.merge(customer); on a customer (already in DB, not altered) i see these two sql commands in log:

Hibernate: update CUSTOMERS set CUS_DESCR=?, CUS_NAME=?, CUS_ENABLED=? where CUS_ID=? Hibernate: delete from CUS_BUS_UNITS where CUS_ID=?

Why is hibernate trying to delete a record from join table? I need only update customer record and possibly records in the join table - depends on if i added or removed business units on the customer. Business units should not be updated, deleted or inserted.

EDIT: My equals/hashCode are (defined in AbstractEntity):

public int hashCode() {
    if (getId() != null) {
        return getId().hashCode();
    }
    return super.hashCode();
}
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    AbstractEntity other = (AbstractEntity) obj;
    if (getId() == null || other.getId() == null) {
        return false;
    }
    if (!getId().equals(other.getId())) {
        return false;
    }
    return true;
}

EDIT 2 Converter for the form:

@FacesConverter("businessUnitConverter")
public class BusinessUnitConverter implements Converter {

    /**
     * {@inheritDoc}
     */
    @Override
    public String getAsString(FacesContext context, UIComponent component, Object object) {
        return ((BusinessUnit) object).getId().toString();
    }


    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        BusinessUnit businessUnit = new BusinessUnit();
        businessUnit.setId(Long.parseLong(value));
        return businessUnit;
    }

}
like image 885
DominikM Avatar asked Feb 15 '13 14:02

DominikM


1 Answers

I found an answer: http://assarconsulting.blogspot.fr/2009/08/why-hibernate-does-delete-all-then-re.html

This behavior is correct due to use of Collection (see linked article). I used Set instead of collection and it works fine.

like image 170
DominikM Avatar answered Nov 15 '22 01:11

DominikM