【问题标题】:Unable to delete parent JPA entity with @OneToMany relationship using Hibernate无法使用 Hibernate 删除具有 @OneToMany 关系的父 JPA 实体
【发布时间】:2016-04-21 16:27:52
【问题描述】:

我在使用 Hibernate 删除与子实体具有@OneToMany 关系的 JPA 实体时遇到了问题,但是当使用 EclipseLink 而不是 Hibernate 作为 JPA 提供程序时,相同的代码可以正常工作。父实体上的注解是@OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)

当使用 Hibernate 时,它​​会尝试将子实体上的连接列设置为 null,但由于该列不允许为 null,因此失败。使用 EclipseLink 时,它首先删除子实体,然后删除作为所需行为的父实体。

我的问题是:

  1. 为什么 Hibernate 和 EclipseLink 的行为不同?我的理解是,JPA2 中的 orphanRemovalCascaseType.REMOVE 功能应该与两个提供程序的功能相同。
  2. 我是否可以在我的代码中进行任何更改,以允许 EclipseLink 和 Hibernate 在删除父实体时功能相同,而无需先删除子实体?一个限制是代码必须与两个 JPA 提供程序一起使用。

我在 SO 上发现了几个类似的问题,但其中大多数要么与 JPA 1.0 相关,使用了已弃用的 Hibernate 注释,要么建议在 @OneToMany 注释上设置 orphanRemoval=true

我使用的Hibernate版本是4.3.10.Final,EclipseLink的版本是2.5.2。

为了演示这个问题,我创建了以下相对简单的示例。

父实体的代码如下:

@Entity
@Table(name="HOUSE")
public class HouseEntity {

    @Id
    @Column(name="HOUSE_ID")
    private int houseId;

    @Column(name="HOUSE_NAME")
    private String houseName;

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)
    @JoinColumn(name = "HOUSE_ID", referencedColumnName = "HOUSE_ID")
    private List<RoomEntity> rooms;

    //Getters, setters, equals, and hashCode omitted
}

子实体的代码如下:

@Entity
@Table(name="ROOM")
public class RoomEntity {

    @Id
    @Column(name="ROOM_ID")
    private int roomId;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "HOUSE_ID", referencedColumnName = "HOUSE_ID")
    private HouseEntity house;

    @Column(name="ROOM_NAME")
    private String roomName;

    //Getters, setters, equals, and hashCode omitted
}

用于删除父实体的EJB代码如下:

@Stateless
public class HouseService {

    @PersistenceContext
    private EntityManager em;

    public void deleteHouse(int houseId) {
        HouseEntity houseEntity = em.find(HouseEntity.class, houseId);
        em.remove(houseEntity);
    }
}

在 Hibernate 中,对数据库执行以下 SQL 语句 update ROOM set HOUSE_ID=null where HOUSE_ID=?ORA-01407: cannot update ("TEST"."ROOM"."HOUSE_ID") to NULL 失败

在 EclipseLink 中,首先执行 SQL 语句 DELETE FROM ROOM WHERE (HOUSE_ID = ?),然后执行 SQL 语句 DELETE FROM HOUSE WHERE (HOUSE_ID = ?)

【问题讨论】:

  • 有趣;这看起来像 Hibernate 中的一个错误。你能确认你是在事务环境中执行的吗? Hibernate 5 会发生什么?
  • 您可以尝试在您的私人列表 房间中将 FetchType.EAGER 设置为 FetchType.LAZY;变量注释
  • 好吧,我在 StringBoot 上试过了,它或多或少都运行良好。它似乎并没有删除房间。如果这很重要,它正在使用 HSQLDialect 方言。
  • @chrylis 是的,代码正在通过 EJB 作为事务的一部分执行。我使用 Hibernate 5.0.7.Final 再次运行了代码,但得到了相同的结果
  • 我建议您将此作为针对 Hibernate 的错误提交,因为更改获取提示不应该影响正确性。

标签: java hibernate jpa jakarta-ee eclipselink


【解决方案1】:

试试下面的

@Entity
@Table(name="HOUSE")
public class HouseEntity {

    @Id
    @Column(name="HOUSE_ID")
    private int houseId;

    @Column(name="HOUSE_NAME")
    private String houseName;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "house", cascade = CascadeType.ALL)
    private List<RoomEntity> rooms;

    //Getters, setters, equals, and hashCode omitted
}


@Entity
@Table(name="ROOM")
public class RoomEntity {

    @Id
    @Column(name="ROOM_ID")
    private int roomId;

    @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "HOUSE_ID", referencedColumnName = "HOUSE_ID", nullable = false)
    private HouseEntity house;

    @Column(name="ROOM_NAME")
    private String roomName;

    //Getters, setters, equals, and hashCode omitted
}

【讨论】:

  • 感谢 Diyoda 我已经尝试了您建议的更改,现在它适用于 Hibernate 和 EclipseLink
  • @Diyoda 您能否在回答中解释为什么此更改有效?
猜你喜欢
  • 2019-07-09
  • 1970-01-01
  • 2013-05-22
  • 2021-12-21
  • 1970-01-01
  • 2021-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多