I've a entity setup that boils down to something like that:
Person (N:1) -> Job (1:N) -> Company
So a person has a java.util.Set
of Job
instances. The set is defined like this:
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Job> jobs = new LinkedHashSet<>();
And the company looks like this:
@Entity
public class Company {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String name;
@OneToMany
private List<Stelle> jobs = new ArrayList<Stelle>();
public String getDisplayText() { return name; }
@Override
public int hashCode() {
int result = 1;
result = 31 * result
+ ((getDisplayText() == null) ? 0 : getDisplayText().hashCode());
return 31 * result + ((getId() == null) ? 0 : getId().hashCode());
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Company))
return false;
return !(getId() == null && ((Company) obj).getId() != null)
|| getId() == null
|| (getId().equals(((Company) obj).getId());
}
// getters + setters
}
I create and attach jobs to a person instance in my frontend. The company is selected and attached to the new Job
entity with a javax.faces.Converter
, where it is fetched from the persistence context via its id.
When I call entityManager.merge(person)
on a person that has two Job
s with the same Company
, I get this exception:
Caused by: java.lang.IllegalStateException: Error occurred while storing
entity [example]. An entity copy [com.company.entity.Company#1] was already
assigned to a different entity [example].
at org.hibernate.event.internal.EventCache.put(EventCache.java:192)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:287)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:153)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:851)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:833)
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:277)
[...]
My problem seems to be that DefaultMergeEventListener.java:113
(Hibernate-4.3.0.CR1) says:
if ( copyCache.containsKey( entity ) &&
( copyCache.isOperatedOn( entity ) ) ) {
LOG.trace( "Already in merge process" );
event.setResult( entity );
}
else { /* fetch entity and put it in copyCache */ }
copyCache
is a java.util.IdentityHashMap
, so my two detached entities are not considered equal for this cache, even if they are for according to their equals()
method.
My question is simple: can I somehow keep using the flow described above or what do I have to alter to get Hibernate to merge this entity graph?
Edited to add: I'm aware of Hibernate: An entity copy was already assigned to a different entity and IllegalStateException: Error occurred while storing entity <entity> An entity copy <entity> was already assigned to a different entity <entity_copy> describing similar problems.