约束违规弹簧JPA仅在某些记录上

时间:2018-05-30 07:57:38

标签: java database spring jpa constraints

我为Dependency实体获得了违反约束的异常,但它只发生在旧记录上。我的最后一项更改是将mappedBy=kpi - 属性添加到名为KPIBusiness的父实体。

我可以删除新创建的具有依赖关系但不包含旧实体的父实体。

KPIBusiness.java:

@Entity
public class KPIBusiness extends KPI {

    private Long businessProcessId;
    private String businessProcess;

    private Long eventId;
    private String event;

    @OneToMany(mappedBy="kpi", fetch = FetchType.EAGER, cascade=CascadeType.ALL)   
    private Set<Dependency> dependencies;
}

Dependency.java

@Entity
@Table(name="dependencies")
public class Dependency {
    @Id
    @GeneratedValue
    private Long did;

    public Long getDid() {
        return did;
    }

    public void setDid(Long did) {
        this.did = did;
    }   
    private AlertConstants.TRIGGER kpiType;

    private Long kpiId;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name="id", nullable=false)  
    private KPIBusiness kpi;
}

例外:

  

引起:org.h2.jdbc.JdbcSQLException:ReferentielleIntegrität   verletzt:“FKSKW30595DULXL90POB2K9KT3I:   PUBLIC.KPIBUSINESS_DEPENDENCIES FOREIGN KEY(DEPENDENCIES_DID)   参考文献PUBLIC.DEPENDENCIES(DID)(33)“       参照完整性约束违规:“FKSKW30595DULXL90POB2K9KT3I:PUBLIC.KPIBUSINESS_DEPENDENCIES FOREIGN   KEY(DEPENDENCIES_DID)REFERENCES PUBLIC.DEPENDENCIES(DID)(33)“; SQL   声明:       从依赖项中删除do =? [23503-196]

我正在使用此代码:

repository.delete(currentKPI);
repository.flush();

我正在考虑使用此代码:

currentKPI.setDependencies(new HashSet<Dependency>());
currentKPI = repository.save(currentKPI);
repository.flush();//HACK delete at first try
repository.delete(currentKPI);
repository.flush();

然而,似乎currentKPI.setDependencies(dependencies);根本不更新依赖项。我使用此代码尝试更改依赖项:

Set<Dependency> dependencies = new HashSet<Dependency>();
for(RemoteKPINames kpi : tcsDependencies.getValue()) {
    Dependency dependency = new Dependency();
    dependency.setKpiId(kpi.getId());
    dependency.setKpiType(kpi.getType());
    dependency.setKpi(data);
    dependencies.add(dependency);
}

log.info("Setting dependencies in data object #={}", dependencies.size());
data.setDependencies(dependencies);

2 个答案:

答案 0 :(得分:1)

<强> EmployeeEntity.java

@Entity
@Table(name = "Employee")
public class EmployeeEntity implements Serializable
{
    private static final long serialVersionUID = -1798070786993154676L;
    @Id
    @Column(name = "ID", unique = true, nullable = false)
    private Integer           employeeId;
    @Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
    private String            firstName;
    @Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
    private String            lastName;

    @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name="EMPLOYEE_ID")
    private Set<AccountEntity> accounts;

    //Getters and Setters Ommited
}

<强> AccountEntity.java

@Entity
@Table(name = "Account")
public class AccountEntity implements Serializable
{
    private static final long serialVersionUID = 1L;
    @Id
    @Column(name = "ID", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer           accountId;
    @Column(name = "ACC_NO", unique = false, nullable = false, length = 100)
    private String            accountNumber;

    @OneToOne (mappedBy="accounts",  fetch = FetchType.LAZY)
    private EmployeeEntity employee;

}

查看上面EmployeeEntity.java源代码中的粗体。它定义了“cascade = CascadeType.ALL”,它实质上意味着EmployeeEntity上发生的任何更改都必须级联到AccountEntity。如果您保存员工,则所有关联的帐户也将保存到数据库中。如果删除员工,则也会删除与该员工关联的所有帐户。很简单。

但是,如果我们只想级联保存操作而不是删除操作,该怎么办?然后我们需要使用下面的代码清楚地指定它。

@OneToMany(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinColumn(name="EMPLOYEE_ID")
private Set<AccountEntity> accounts;

现在,只有在使用员工实例调用save()或persist()方法时,才会保留帐户。如果在会话中调用任何其他方法,则其效果不会影响/级联到帐户。

JPA级联类型

Java Persistence Architecture支持的级联类型如下:

  1. CascadeType.PERSIST:表示save()或persist()操作 级联到相关实体。
  2. CascadeType.MERGE:表示相关实体在合并时合并 拥有实体合并。
  3. CascadeType.REFRESH:对refresh()做同样的事情 操作
  4. CascadeType.REMOVE:删除与之关联的所有相关实体 删除拥有实体时的此设置。
  5. CascadeType.DETACH:如果是“手册”,则分离所有相关实体 分离“发生。
  6. CascadeType.ALL:是上述所有级联的简写 操作。

答案 1 :(得分:1)

您的级联用于从父级(KPIBusiness)到子级(Dependency)。它不会以其他方式工作。您的Dependency无法(神奇地)从包含它的任何集合中删除。

选项1:

Dependency 中删除KPIBusiness删除它。请在下面找到示例代码:

// start a transaction
Dependency dependencyToBeDeleted;
KPIBusiness kpiBusiness;
...
kpiBusiness.getDependencies().remove(dependencyToBeDeleted);
dependencyRepository.remove(dependencyToBeDeleted);
// commit the transaction

选项2:

使用@OneToManyExample)扩展Set<Dependencies>的{​​{1}}注释。然后,它足以从orphanRemoval=true中的集合中删除Dependency,并且当JPA不再被引用时,它将自动将其从数据库中删除。

确保您完全了解 DELETE级联 orphanRemoval 的用法。得到错误总是更好,而不是JPA默默地删除你从未打算删除的东西。