传播级联删除引发外键约束失败

时间:2019-05-29 14:53:20

标签: java hibernate jpa spring-data-jpa cascade

我正在将Spring Boot(2.1.0.RELEASE)与Spring Data JPA一起使用。数据库是MySQL。

链式级联删除时遇到一些问题。

我有以下模型:

enter image description here

我不使用@ManyToMany,因为我需要在生成的表中添加其他字段,所以我的实体如下(已删除了无用的属性):

@Audited
@Entity
@Table(name = "request")
public class Request {

    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private Resource resource;

}


@Audited
@Entity
@Table(name = "resource")
public class Resource {

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "resource")
    private Set<ResourceArticle> resourceArticles;

}

@Audited
@Entity
@Table(name = "resource_article")
public class ResourceArticle {

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "article_id")
    private Article article;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "resource_id")
    private Resource resource;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "resourceArticle")
    private Set<ResourceArticleOption> options;

}

@Audited
@Entity
@Table(name = "resource_article_option")
public class ResourceArticleOption {

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "option_id")
    private Option option;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "resource_article_id")
    private ResourceArticle resourceArticle;

}

然后从我的经理那里,我发出扩展delete的请求CrudRepository

/* Repositroy */
public interface RequestRepository extends CrudRepository<Request, Long> {
}

/* Manager */
@Transactional
@Component("requestMgr")
public class RequestManager {

    @Autowired
    RequestRepository requestRepository;

    public void delete(Request request) {
        requestRepository.delete(request);
    }

}

/* Viewmodel */
public class RequestVm {

    @WireVariable
    private RequestManager requestMgr;

    public void deleteRequest(Request req) {
        requestMgr.delete(req);
    }

}

错误是:

  

由于:java.sql.SQLException:无法删除或更新父级   行:外键约束失败   ({my_dbresource_article,约束   FK5wqvprkwx05fb5hgt6w9h7nbk外键(resource_id)参考   resourceid))

启用跟踪时的输出:

binding parameter [1] as [BIGINT] - [1]
delete from resource where id=?
binding parameter [1] as [BIGINT] - [1]
SQL Error: 1451, SQLState: 23000
(conn=30) Cannot delete or update a parent row: a foreign key constraint fails (`my_db`.`resource_article`, CONSTRAINT `FK5wqvprkwx05fb5hgt6w9h7nbk` FOREIGN KEY (`resource_id`) REFERENCES `resource` (`id`))

我需要CascadeType.ALL才能持久和删除。

我可以通过在删除前将引用设置为null来打破链条,但这会导致数据库中的孤立记录。

这里最好的策略是什么?

1 个答案:

答案 0 :(得分:0)

我通过在每个关系中删除非关系所有者的实体来使其正常工作。

@ManyToMany中的级联删除不仅应用于链接表,而且还应用于关系的另一端。

当从@ManyToMany关联中删除时,这是一个众所周知的问题(例如,here对此有很好的解释),但是我没有注意,因为我的注释不是直接的@ManyToMany但是有两个@OneToMany关联,尽管我JPA会像简单的@OneToMany关系那样级联删除,但似乎我错了。

在删除请求之前,我曾使用@preRemove来清理该关系:

ResourceArticle中:

@PreRemove
public void preRemove() {
    article.getResourceArticles().remove(this);
}

ResourceArticleOption中:

@PreRemove
public void preRemove() {
    option.getResourceArticleOptions().remove(this);
}

然后一切正常。