Search code examples
springhibernatespring-data-jpaall-delete-orphan

orphanRemoval causes error with lazy loaded collection


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?


Solution

  • 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.