删除实体时休眠将外键设置为空

Posted

技术标签:

【中文标题】删除实体时休眠将外键设置为空【英文标题】:Hibernate set foreign key to null when delete entity 【发布时间】:2013-06-11 16:16:25 【问题描述】:

我有以下休眠实体:

@Entity
@Table(name = "model_view")
public class ModelView 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "modelView_id")
    private Integer id;

    @ManyToOne
    @NotNull
    @JoinColumn(name = "page_id", nullable = false, insertable = true, updatable = true)
    private Page page;

    /* getters and setters */

还有:

@Entity
public class Page 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "page_id")
    private Integer id;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "page_id")
    @IndexColumn(name = "modelView_id")
    private Set<ModelView> modelViews = new HashSet<ModelView>();

    /* getters and setters */

当我在 DAO 中删除实体 «ModelView» 时出现异常:

ORA-01407: unable to replace ("MODEL_VIEW"."PAGE_ID") to NULL

怎么了?为什么hibernate在删除前设置外键为NULL?

【问题讨论】:

【参考方案1】:

为什么hibernate在删除前设置外键为NULL?

Hibernate 尝试通过将 FK 清空来取消引用您尝试删除的记录。不幸的是,在大多数情况下,FK 不能为空。您必须告诉 Hibernate 在删除 Page 记录时不要更新 ModelView 实例。

尝试在page 中的@JoinColumn 映射上将insertableupdatable 更改为false ModelView

@JoinColumn(name = "page_id", nullable = false, insertable = false, updatable = false)

使用这些值时,ModelView 记录将保留。同样,如果您强制执行参照完整性,这将不起作用。要解决这个问题,您需要打开级联删除。我注意到在您的代码中您已经在使用 CascadeType.ALL 应该可以正常工作。

这是一个解释这些字段的 SO Q&A:

In JPA why and how to use insertable and updatable parameter?

我有一个类似的问题,通过使用 false 来解决这些值。

How can I map "insert='false' update='false'" on a composite-id key-property which is also used in a one-to-many FK?

【讨论】:

这不是我的解决方案,因为在这种情况下,我在插入实体 «ModelView» 时遇到相同的错误(ORA-01400:无法将 NULL 插入(“MODEL_VIEW”。“PAGE_ID”))。我尝试将 FK 设置为可为空,但这不是一个好主意。还有其他解决办法吗? 这个建议的解决方案应该也可以用 INSERT 语句解决这个问题。当您将insertableupdatable 设置为false 时,您是在告诉Hibernate 您将手动处理保存对ModelView 记录的修改。这意味着您需要先插入/更新Page 记录,然后在ModelView 上设置FK,然后独立保存这些记录,最好是全部在1 个事务中。如果你这样做,你永远不会遇到 FK 为 NULL 的情况。 @AnEi 如果你仍然有这些错误,你能分享一些你用来导致它的代码吗? 将“insertable = false, updatable = false”添加到@JoinColumn 规范对我来说起到了作用。谢谢!然后 Hibernate 问题只会按正确的顺序删除,不会尝试将 FK 更新为 null。 @MaksimGumerov 你不应该在ModelView.page 上设置updatable = false,你应该在Page.modelViews 上设置它。仍然可以通过在代码中设置 ModelView.page 来更新数据库中的 ModelView.page_id 字段,只是无法使用代码中的 Page.modelViews 更新 FK。如果您仍然感到困惑,请提出一个新问题,这样您将获得更多帮助。随时在这里链接到新问题,我会看看。

以上是关于删除实体时休眠将外键设置为空的主要内容,如果未能解决你的问题,请参考以下文章

实体框架,查找方法将外键留空

HIbernate 无法删除具有外键的实体。外键设置为空

Entity Framework Core 实体关系的配置

首次使用实体框架代码时将外键设置为 null

Entity Framework Core 实体关系的配置

如果孩子为空,休眠ManyToMany删除另一边