Found shared references to a collection org.hibernate.HibernateException

121,073

Solution 1

Hibernate shows this error when you attempt to persist more than one entity instance sharing the same collection reference (i.e. the collection identity in contrast with collection equality).

Note that it means the same collection, not collection element - in other words relatedPersons on both person and anotherPerson must be the same. Perhaps you're resetting that collection after entities are loaded? Or you've initialized both references with the same collection instance?

Solution 2

I had the same problem. In my case, the issue was that someone used BeanUtils to copy the properties of one entity to another, so we ended up having two entities referencing the same collection.

Given that I spent some time investigating this issue, I would recommend the following checklist:

  • Look for scenarios like entity1.setCollection(entity2.getCollection()) and getCollection returns the internal reference to the collection (if getCollection() returns a new instance of the collection, then you don't need to worry).

  • Look if clone() has been implemented correctly.

  • Look for BeanUtils.copyProperties(entity1, entity2).

Solution 3

Explanation on practice. If you try to save your object, e.g.:

Set<Folder> folders = message.getFolders();
   folders.remove(inputFolder);
   folders.add(trashFolder);
   message.setFiles(folders);
MESSAGESDAO.getMessageDAO().save(message);

you don't need to set updated object to a parent object:

message.setFiles(folders);

Simple save your parent object like:

Set<Folder> folders = message.getFolders();
   folders.remove(inputFolder);
   folders.add(trashFolder);
   // Not set updated object here
MESSAGESDAO.getMessageDAO().save(message);

Solution 4

I have experienced a great example of reproducing such a problem. Maybe my experience will help someone one day.

Short version

Check that your @Embedded Id of container has no possible collisions.

Long version

When Hibernate instantiates collection wrapper, it searches for already instantiated collection by CollectionKey in internal Map.

For Entity with @Embedded id, CollectionKey wraps EmbeddedComponentType and uses @Embedded Id properties for equality checks and hashCode calculation.

So if you have two entities with equal @Embedded Ids, Hibernate will instantiate and put new collection by the first key and will find same collection for the second key. So two entities with same @Embedded Id will be populated with same collection.

Example

Suppose you have Account entity which has lazy set of loans. And Account has @Embedded Id consists of several parts(columns).

@Entity
@Table(schema = "SOME", name = "ACCOUNT")
public class Account {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "account")
    private Set<Loan> loans;

    @Embedded
    private AccountId accountId;

    ...
}

@Embeddable
public class AccountId {
    @Column(name = "X")
    private Long x;
    
    @Column(name = "BRANCH")
    private String branchId;
    
    @Column(name = "Z")
    private String z;

    ...
}

Then suppose that Account has additional property mapped by @Embedded Id but has relation to other entity Branch.

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "BRANCH")
@MapsId("accountId.branchId")
@NotFound(action = NotFoundAction.IGNORE)//Look at this!
private Branch branch;

It could happen that you have no FK for Account to Brunch relation id DB so Account.BRANCH column can have any value not presented in Branch table.

According to @NotFound(action = NotFoundAction.IGNORE) if value is not present in related table, Hibernate will load null value for the property.

If X and Y columns of two Accounts are same(which is fine), but BRANCH is different and not presented in Branch table, hibernate will load null for both and Embedded Ids will be equal.

So two CollectionKey objects will be equal and will have same hashCode for different Accounts.

result = {CollectionKey@34809} "CollectionKey[Account.loans#Account@43deab74]"
 role = "Account.loans"
 key = {Account@26451} 
 keyType = {EmbeddedComponentType@21355} 
 factory = {SessionFactoryImpl@21356} 
 hashCode = 1187125168
 entityMode = {EntityMode@17415} "pojo"

result = {CollectionKey@35653} "CollectionKey[Account.loans#Account@33470aa]"
 role = "Account.loans"
 key = {Account@35225} 
 keyType = {EmbeddedComponentType@21355} 
 factory = {SessionFactoryImpl@21356} 
 hashCode = 1187125168
 entityMode = {EntityMode@17415} "pojo"

Because of this, Hibernate will load same PesistentSet for two entities.

Solution 5

Reading online the cause of this error can be also an hibernate bug, as workaround that it seems to work, it is to put a:

session.clear()

You must to put the clear after getting data and before commit and close, see example:

//getting data
SrReq sr = (SrReq) crit.uniqueResult();
SrSalesDetailDTO dt=SrSalesDetailMapper.INSTANCE.map(sr);
//CLEAR            
session.clear();
//close session
session.getTransaction().commit();
session.close();
return dt;

I use this solution for select to database, for update or insert i don't know if this solution can work or can cause problems.

My problem is equal at 100% of this: http://www.progtown.com/topic128073-hibernate-many-to-many-on-two-tables.html

Share:
121,073
nightingale2k1
Author by

nightingale2k1

---- Grails and PHP programmer --- love doing web jobs

Updated on July 05, 2022

Comments

  • nightingale2k1
    nightingale2k1 almost 2 years

    I got this error message:

    error: Found shared references to a collection: Person.relatedPersons

    When I tried to execute addToRelatedPersons(anotherPerson):

    person.addToRelatedPersons(anotherPerson);
    anotherPerson.addToRelatedPersons(person);
    
    anotherPerson.save();
    person.save();
    

    My domain:

    Person {
    
     static hasMany = [relatedPersons:Person];
    
    }
    

    any idea why this happens ?

  • nightingale2k1
    nightingale2k1 over 14 years
    found the problem. I did a mistake by typing person.relatedPerson = anotherPerson ; somewhere in the code .... doh.
  • vacuum
    vacuum over 11 years
    what class should implement clone() ?
  • Rubens Mariuzzo
    Rubens Mariuzzo almost 9 years
    @vacuum, the domain model.
  • vashishth
    vashishth almost 8 years
    what would be the solution here?
  • Tiina
    Tiina over 6 years
    yes, but why hibernate treats this as a problem? An entity has a collection like a ManyToMany field, and the value is set by looking up from another entity.
  • Bhushan
    Bhushan about 6 years
    @vashishth Earlier, I was doing entity1.setCollection(entity2.getCollection()). I solved it by entity1.setCollection(new HashSet(entity2.getCollection()))
  • Kalle Richter
    Kalle Richter about 6 years
    This is unnecessarily hard to read because class names are lower case and the code contains unnecessary assignments.
  • gtiwari333
    gtiwari333 almost 6 years
    Thanks for the checklist. In my case I was doing BeanUtils.copyProperties(oldRec, newRec) in 'clone()` method. I updated the BeanUtils.copyProperties to skip the newly added ManyToMany field as BeanUtils.copyProperties(oldRec, newRec, newCollectionField).
  • ichalos
    ichalos over 4 years
    I am sorry, but this is not really helpful as it's just a simple mistake on your side.
  • Fildor
    Fildor almost 4 years
    Could you please edit to make this a little more readable?
  • Artiow
    Artiow over 2 years
    You saved my day. I had the same issue, but because of non-unique composite key for many-to-many relation. Thanks a lot! Where can I read about this Hibernate feature?
  • GreenROBO
    GreenROBO over 2 years
    @Bhushan - Got helped from your comment. Thanks