简体   繁体   English

休眠更新到OneToMany集合的唯一约束违规

[英]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 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') Service s to become deleted, when I call setServices with a new HashSet . 当我使用新的HashSet调用setServices时,我希望所有“旧”(=“孤立”) Service将被删除。 What I am doing wrong? 我做错了什么? TIA! TIA!

Just calling .clear() on the set may not be enough. 仅在集合上调用.clear()可能还不够。 Likely its requiring an explicit call to remove() on each component of the set before clearing it. 可能需要在清除集之前对集合的每个组件进行显式调用remove()。

please try adding something like this before clearing the set to see if that solves the issue 请先尝试添加类似的内容,然后再清除该集合以查看是否可以解决问题

this.services.forEach(service -> {licenseRepository.remove(service)});

Try to clear the list before setting the services: 尝试设置服务之前 清除列表:

license.getServices().clear();

And then 接着

license.getServices.add("firstService");
licenseRepository.save(license);

UPDATE 更新

To make this work, it is important to implement the equals and hashCode methods. 为了使这项工作有效,实现equalshashCode方法很重要。 I'm using apache commons lang library 我正在使用apache commons lang库

@Override
public int hashCode() {
    return new HashCodeBuilder().append(idService).toHashCode();
}

@Override
public boolean equals(Object obj) {
    if (!(obj instanceof Service))
        return false;

    Service other = (Service) obj;

    return new EqualsBuilder()
            .append(this.idService, other.idService)
            .isEquals();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM