Hibernate - @Elementcollection - Strange Delete/Insert Behavior

Hibernate - @ElementCollection - Strange delete/insert behavior

The problem is somehow explained in the page about ElementCollection of the JPA wikibook:

Primary keys in CollectionTable


The JPA 2.0 specification does not
provide a way to define the Id in the
Embeddable. However, to delete or
update a element of the
ElementCollection mapping, some unique
key is normally required. Otherwise,
on every update the JPA provider would
need to delete everything from the
CollectionTable for the Entity, and
then insert the values back.
So, the
JPA provider will most likely assume
that the combination of all of the
fields in the Embeddable are unique,
in combination with the foreign key
(JoinColunm(s)). This however could be
inefficient, or just not feasible if
the Embeddable is big, or complex.

And this is exactly (the part in bold) what happens here (Hibernate doesn't generate a primary key for the collection table and has no way to detect what element of the collection changed and will delete the old content from the table to insert the new content).

However, if you define an @OrderColumn (to specify a column used to maintain the persistent order of a list - which would make sense since you're using a List), Hibernate will create a primary key (made of the order column and the join column) and will be able to update the collection table without deleting the whole content.

Something like this (if you want to use the default column name):

@Entity
public class Person {
...
@ElementCollection
@CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID"))
@OrderColumn
private List<Location> locations;
...
}

References

  • JPA 2.0 Specification

    • Section 11.1.12 "ElementCollection Annotation"
    • Section 11.1.39 "OrderColumn Annotation"
  • JPA Wikibook

    • Java Persistence/ElementCollection

@ElementCollection, @CollectionTable and Enum - Strange delete/insert behavior

@OrderColumn solved the problem

Hibernate - delete insert db commands about ElementCollection

Clearly the JPA sees that the objects are not equal are clears and re-inserts.
Please try overriding the equals() and hashcode() for the Embeddable object. With default implementation, object is considered equal by reference alone, which would have not been in your case.

hibernate insert to a collection causes a delete then all the items in the collection to be inserted again

I have inserts acting the way I expect them to now. Thanks to Pascal and z5h, I have learned a lot. I believe I have the hashCode and equals implemented correctly. This never solved the problem for me though. Instead I have implemented an Intermediate Entity.

For what it is worth below are the mapping in my Employee, CohortGroup, and now CohortGroupMemeber classes.

Employee:

@OneToMany(mappedBy="member")
public List<CohortGroupMember> getMemberGroups(){
return memberGroups;
}
public void setMemberGroups(List<CohortGroupMember> grps){
memberGroups = grps;
}

CohortGroupMember

@ManyToOne
@JoinColumn(name="USERID")
public Employee getMember(){
return emp;
}
public void setMember(Employee e){
emp = e;
}
@ManyToOne
@JoinColumn(name="COHORT_GROUPID")
public CohortGroup getGroup(){
return group;
}
public void setGroup(CohortGroup cg){
group = cg;
}

CohortGroup

@OneToMany(mappedBy="group")
public List<CohortGroupMember> getMembers(){
return members;
}
public void setMembers(List<CohortGroupMember> emps){
members = emps;
}

The book I followed for this is Java Persistence with Hibernate chapter 7.2.3

Removing element from JPA element Collection

You need to identify the object you want to remove (obviously without id since there is none, but the combination of other fields should be unique), remove it from owner entity's collection and merge the entity.

Since there is no id, JPA will delete all elements from collection, and insert them again but without the removed one.

Branch toBoRemoved = ...; // find out which element needs to be removed
for (Iterator i = entity.getBranches().iterator(); i.hasNext();) {
Branch b = (Branch)i.next();
if (b.equals(toBeRemoved)) { // you'll need to implement this
i.remove();
}
}
entityManager.merge(entity);

JPA - Adding and Removing elements in List with ElementCollection

What I ended up doing was creating an entity of my own instead of using annotations to create the fields table, this is the Store entity:

@Entity
public class Store {
@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
@OrderBy("index ASC")
private List<Item> itemsList;

@Column
private int index = 0;

public List<Item> getItemsList() {
return itemsList;
}

public void setItemsList(List<Item> itemsList) {
this.itemsList = itemsList;
}

public void addToItemList(String item) {
final Item newItem = new Item();
newItem.setStoreId(this.id);
newItem.setValue(item);
newItem.setIndex(index++);
this.itemsList.add(newItem);
}
}

this is the Item entity which the store will hold a list of:

@Entity
@IdClass(Ids.class)
public class Item {

@Id
private long storeId;

@Id
private int index;

@Column
private String value;

public long getStoreId() {
return storeId;
}

public void setStoreId(long storeId) {
this.storeId = storeId;
}

public int getIndex() {
return index;
}

public void setIndex(int index) {
this.index = index;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
}

class Ids implements Serializable { // each id will be composed of storeId + index
long storeId;
int index;
}

strange sql behavior when do deleting relation for many-to-many in JPA

I've not checked that this explanation is true, but it has good points.

Without any index column, a List is in fact a bag: no order, and duplicates allowed. So Hibernate considers it possible that you have the same role twice in the list of roles of a user.

So issuing delete from user_role where user_id = ? and role_id = ? is not possible because it would potentially remove several roles instead of just the one you removed from the list.

Try adding an index column, or using a Set<Role> instead of a List<Role>.



Related Topics



Leave a reply



Submit