The best place to *find* answers to programming/development questions, imo, however it's the *worst* place to *ask* questions (if your first question/comment doesn't get any up-rating/response, then u can't ask anymore questions--ridiculously unrealistic), but again, a great reference for *finding* answers.

My Music (Nickleus)

20121219

javax.persistence.PersistenceException: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance

i was trying to perform a simple delete operation in our ejb3/hibernate application and was getting the following error:
javax.persistence.PersistenceException: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.myapp.domainentitiesEJB3.party.Party.references
Transaction failed


the problem was in our Party entity class:
public void setReferences(List<Reference> references_) {
    this.references = references_;
}


it had to be changed to:
public void setReferences(List<Reference> references_) {
    if(this.references != null && references_ != null && !references_.isEmpty()){
        this.references.clear();
        for(int i = 0; i < references_.size(); i++){
            Reference lp = references_.get(i);
                this.references.add(lp);
        }
        this.references.addAll(references_);
    }
    else this.references.clear();
}


the problem was that we were trying to overwrite the collection, but by doing that, hibernate lost "ownership" of the collection and threw an error. it's best explained in the article Let's Play "Who Owns That Collection?" With Hibernate

4 comments:

  1. Do you need the loop? Could you just use this.references.addAll(references_) ?

    ReplyDelete
    Replies
    1. lol, yeah ur probably right, thx :)

      Delete
    2. As per the article link provided in this description this solution doesn't work I guess. In my case more problems crop up after implementing this solution. What I did is made this method as private

      private void setReferences(List references_) {
      this.references = references_;
      }

      define another method

      public void addReferences(List references_) {
      this.references.clear();
      this.references.addAll(references_);
      }
      this method is used whenever you want to fill references.

      This solution perfectly worked me. Any comments please....

      Delete
  2. When I read in various places that hibernate didn't like you to assign to a collection, I assumed that the safest thing to do would obviously be to make it final like this:

    class User {
    private final Set roles = new HashSet<>();

    public void setRoles(Set roles) {
    this.roles.retainAll(roles);
    this.roles.addAll(roles);
    }
    }

    However, this doesn't work, and you get the dreaded "no longer referenced" error, which is actually quite misleading in this case.

    It turns out that hibernate calls your setRoles method AND it wants its special collection class installed here, and won't accept your collection class. This had me stumped for a LONG time, despite reading all the warnings about not assigning to your collection in your set method.

    So I changed to this:

    public class User {
    private Set roles = null;

    public void setRoles(Set roles) {
    if (this.roles == null) {
    this.roles = roles;
    } else {
    this.roles.retainAll(roles);
    this.roles.addAll(roles);
    }
    }
    }

    So that on the first call, hibernate installs its special class, and on subsequent calls you can use the method yourself without wrecking everything. If you want to use your class as a bean, you probably need a working setter, and this at least seems to work.

    ReplyDelete