1

I use hibernate 5.0.8 and spring data jpa 1.10.1

Given these entities

class Model {
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
    @JoinColumn(nullable = false)
    private Configuration configuration;

    //more fields and methods
}

class Configuration {
    @OneToMany(mappedBy = "configuration", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Setting> settings = new ArrayList<>();

    //more fields and methods
    //settings is never assigned again - I use settings.add(...) and settings.clear()
}

class Setting {
    @ManyToOne
    @JoinColumn(nullable = false)
    private Configuration configuration;

    //more fields and methods
}

Model is the master, but multiple models can use the same configuration. The cascading on configuration in Model is required, because if I change anything in the Configuration, I want it to be applied in all Models using this Configuration

Now when I retrieve an existing Model with a Configuration that has settings, and save this Model, without applying any changes to the settings I get following exception

@Transactional
public void doSomething() {
    Model model = modelRepository.findOne(0);
    //change something in the model, but no changes are made in its configuration
    //or do nothing
    modelRepository.save(model);
}

I get the following exception

A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: Configuration.settings

I suspect this has something to do with the settings being lazy loaded and hibernate trying to merge an empty list into the configuration.

What am I doing wrong?

Harald
  • 33
  • 4
  • turn on logging and see what is getting fetched and when. If you are returning unmodifiable collections, show the code, and check that JPA is set to use field access instead of method access on your attributes or it might be using those collections to see what's changed instead. – Chris Mar 08 '18 at 13:30

2 Answers2

0

Check the getters and setters of the objects you are trying to clean up as orphans while dereferencing:

Try and use :

    public void setChildren(Set<Child> aSet) {
        //this.child= aSet; //Results in this issue
        //change to  

        this.child.clear();
        if (aSet != null) {
            this.child.addAll(aSet);
        } }
RCInd
  • 344
  • 2
  • 13
  • I do not have any setters on collections (i wrote addChild and removeChild methods). Getters always return a new unmodifiable collection, to make sure entities can only be added to collections through the addChild and removeChild method The problem I have is that I even get this exception when nothing has changed. – Harald Mar 08 '18 at 10:27
  • this means that the entity is detached when you are trying to save it. Are you sure this is happening in one transaction and that the txMgr has kicked in? If possible, can you share the business method where you are making changes to this entity – RCInd Mar 08 '18 at 11:26
  • Also can you add the getters setters and try again? For lazy evaluation hibernate users proxy on getters/setter for collcations, Perhaps that would be causing this. Please give it a try after adding getters and setters and post Ecceptions if any – RCInd Mar 08 '18 at 11:30
  • I've added getters and setters, but still the same. I've changed my business method to just retrieving the entity and then saving it again, but I still get the same exception. Could it be perhaps because I have the quite unusual cascading on the ManyToOne relation in Model? – Harald Mar 08 '18 at 13:03
  • Can u try to add cascade type all and try o persist it with "persist()" rather than save? – RCInd Mar 08 '18 at 13:40
  • You can also try and persist it using saveOrUpdate(). We can work towards a solution from there downwards to reach the root cause. – RCInd Mar 08 '18 at 13:41
0

The problem was being caused by using enableLazyInitialization from the hibernate-enhance-maven-plugin. I still have no idea why it was causing this error, but removing this plugin resolved the issue.

I used this plugin, because I wanted to lazy load a large String field in Model that I would cache in the application. I will now change it to a OneToOne relation that is fetched lazily.

Harald
  • 33
  • 4