Paul H
Paul H

Reputation: 2114

Unable to delete parent JPA entity with @OneToMany relationship using Hibernate

I've hit a problem when using Hibernate to delete a JPA entity that has a @OneToMany relationship with a child entity, but the same code works fine when using EclipseLink instead of Hibernate as the JPA provider. The annotation on the parent entity is @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)

When using Hibernate it attempts to set the join column on the child entity to null which fails as the column does not allow nulls. When using EclipseLink it deletes the child entities first and then deletes the parent entity which is the desired behaviour.

My questions are:

  1. Why is the behaviour different between Hibernate and EclipseLink? My understand that the orphanRemoval and CascaseType.REMOVE features in JPA2 should function that same with both providers.
  2. Is there anything I can change in my code to allow both EclipseLink and Hibernate to function the same when deleting the parent entity, without deleting the child entities first? One constraint is that code must work with both JPA providers.

I've found several similar questions on SO, however most of them either relate to JPA 1.0, using depreciated Hibernate annotations or suggest setting orphanRemoval=true on the @OneToMany annotation.

The version of Hibernate I'm using is 4.3.10.Final and the version of EclipseLink is 2.5.2.

To demonstrate the problem I've created the following relatively simple example.

The code for the parent entity is as follows:

@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
}

The code for the child entity is as follows:

@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
}

The EJB code used to delete the parent entity is as follows:

@Stateless
public class HouseService {

    @PersistenceContext
    private EntityManager em;

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

In Hibernate the following SQL statement is executed against the database update ROOM set HOUSE_ID=null where HOUSE_ID=? which fails with a ORA-01407: cannot update ("TEST"."ROOM"."HOUSE_ID") to NULL

In EclipseLink the SQL statement DELETE FROM ROOM WHERE (HOUSE_ID = ?) is executed first and then the SQL statement DELETE FROM HOUSE WHERE (HOUSE_ID = ?) is executed.

Upvotes: 3

Views: 6172

Answers (1)

diyoda_
diyoda_

Reputation: 5420

Try the following

@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
}

Upvotes: 1

Related Questions