无法使用 Hibernate 删除具有@OneToMany 关系的父 JPA 实体
Unable to delete parent JPA entity with @OneToMany relationship using Hibernate
我在使用 Hibernate 删除与子实体具有 @OneToMany
关系的 JPA 实体时遇到了问题,但是当使用 EclipseLink 而不是 Hibernate 作为 JPA 提供程序时,相同的代码工作正常。父实体上的注释是 @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)
使用 Hibernate 时,它会尝试将子实体上的连接列设置为 null,但由于该列不允许 null 而失败。使用 EclipseLink 时,它首先删除子实体,然后删除所需行为的父实体。
我的问题是:
- 为什么 Hibernate 和 EclipseLink 的行为不同?我的理解是 JPA2 中的
orphanRemoval
和 CascaseType.REMOVE
功能应该与两个提供者的功能相同。
- 有什么我可以更改我的代码以允许 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 = ?)
。
尝试以下方法
@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
}
我在使用 Hibernate 删除与子实体具有 @OneToMany
关系的 JPA 实体时遇到了问题,但是当使用 EclipseLink 而不是 Hibernate 作为 JPA 提供程序时,相同的代码工作正常。父实体上的注释是 @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)
使用 Hibernate 时,它会尝试将子实体上的连接列设置为 null,但由于该列不允许 null 而失败。使用 EclipseLink 时,它首先删除子实体,然后删除所需行为的父实体。
我的问题是:
- 为什么 Hibernate 和 EclipseLink 的行为不同?我的理解是 JPA2 中的
orphanRemoval
和CascaseType.REMOVE
功能应该与两个提供者的功能相同。 - 有什么我可以更改我的代码以允许 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 = ?)
。
尝试以下方法
@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
}