Q:

Unique constraint violation on hibernate update to OneToMany collection

I have the following entities:
@Entity
public class License  {

     // ...

    @OneToMany(mappedBy = "license", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
    private Set<Service> services = new HashSet<>();

    // ...

    protected void setServices(Set<String> services) {
        this.services.clear();
        if (services != null) {
            this.services.addAll(services.stream().map(s -> new Service(this, s)).collect(toSet()));
        }
    }
}

@Entity
@Table(uniqueConstraints = @UniqueConstraint(name = "UQ_lic_service", columnNames = { "license_id", "service" }))
public class Service {

    // ...

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "license_id", nullable = false)
    private License license;

    @Column(nullable = false, length = 255)
    private String service;

    protected Service(License license, String service) {
        this.license = license;
        this.service = service;
    }
}

Now I need to update the License like:
    License license = getSomeExistingLicenseWithServices(...);
    // The existing license has two services "firstService", "secondService"
    HashSet<String> services = new HashSet<>();
    services.add("firstService");
    license.setServices(services);
    licenseRepository.save(license); // A spring-data-jpa-repository

Running this, I get the following exception:
Caused by: org.h2.jdbc.JdbcSQLException: Eindeutiger Index oder Primärschlüssel verletzt: "UQ_LIC_SERVICE_INDEX_8 ON PUBLIC.SERVICE(LICENSE_ID, SERVICE) VALUES (1, 'firstService', 1)"
Unique index or primary key violation: "UQ_LIC_SERVICE_INDEX_8 ON PUBLIC.SERVICE(LICENSE_ID, SERVICE) VALUES (1, 'firstService', 1)"; SQL statement:
insert into service (id, lock_no, license_id, service) values (null, ?, ?, ?) [23505-196]

I expected all 'old' (='orphaned') Services to become deleted, when I call setServices with a new HashSet. What I am doing wrong? TIA!

A:

Just calling .clear() on the set may not be enough.  Likely its requiring an explicit call to  remove() on each component of the set before clearing it.
please try adding something like this before clearing the set to see if that solves the issue
this.services.forEach(service -> {licenseRepository.remove(service)});

