有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

hibernate更新到OneToMany集合时违反java唯一约束

我拥有以下实体:

@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;
    }
}

现在我需要更新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

运行此操作时,我得到以下异常:

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]

当我用一个新的HashSet调用setServices时,我希望所有的“旧的”(=“孤立的”)Service都被删除。我做错了什么?蒂亚


共 (2) 个答案

  1. # 1 楼答案

    在设置服务之前,请尝试清除列表:

    license.getServices().clear();
    

    然后

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

    更新

    为了实现这一点,重要的是实现equalshashCode方法。我正在使用ApacheCommonsLang库

    @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();
    }
    
  2. # 2 楼答案

    只是打电话。集合上的clear()可能不够。在清除集合的每个组件之前,可能需要显式调用remove()

    请在清除集合之前尝试添加类似的内容,以查看这是否解决了问题

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