Bouki
Bouki

Reputation: 1359

Save a model with a relation OneToMany

Hi I have models like this :

public class Person extends Model {
...
    @OneToMany(orphanRemoval = true, mappedBy = "person")
    @Cascade({ CascadeType.ALL })
    public List<Contact> infos = new ArrayList<Contact>();
}

public class Contact extends Model {
...
   @ManyToOne(optional = false)
   public Person person;
}

And I have a method in my controller like this :

public static void savePerson(Person person) {
    person.save();
    renderJSON(person);
}

My issue is that when I try to save a person with savePerson() I have this error (only if my list of Person isn't empty) :

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

I don't understand the error message because it appears if the list was previously empty or not.

Upvotes: 3

Views: 2687

Answers (1)

mcls
mcls

Reputation: 9774

I had a very similar problem today.

The problem is that you can't just assign a new Collection to the 'infos' List, because then Hibernate gets confused. Play does this automatically when you use Person as a parameter in the controller. To solve this you need to modify the getters and setters for 'infos' so that it won't instantiate a new Collection / List.

This is the simplest solution I've found so far:

public class Person extends Model {
// ... 
  public List<Contact> getInfos() {
    if (infos == null) infos = new ArrayList<Contact>();
    return infos;
  }

  public void setInfos(List<Contact> newInfos) {
    // Set new List while keeping the same reference
    getInfos().clear();  
    if (newInfos != null) {
      this.infos.addAll(newInfos);
    }
  }
// ...
}

And then in your controller:

public static void savePerson(Person person) {
    person.merge();
    person.save();
    renderJSON(person);
}

Upvotes: 1

Related Questions