Question

I have 2 EJB 3 Entity Beans:

@Entity
public class Organisation
{
    @Id
    @Column(length = 64)
    private String guid;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @JoinColumn(name = "home_unit_fk", nullable = true)
    private Unit homeUnit;          
}

@Entity
public class Unit
{
    @Id
    @Column(length = 64)
    private String guid;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "organisation_fk", nullable = false)
    private Organisation organisation;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_unit_fk", nullable = true)
    private Unit parentUnit;

    @OneToMany(mappedBy = "parentUnit", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @OrderBy("shortName")
    @OptimisticLock(excluded = true)
    private Set<Unit> childUnits;   
}

If I do a delete on the Organisation using standard Dao :

public int deleteByGuid(final String guid) 
{
    final Query query = entityManager.createQuery("delete from " + getPersistentClass().getName() + " where guid = :guid");
    query.setParameter("guid", guid);
    return query.executeUpdate();
}

But I get the following exception:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (config.unit, CONSTRAINT FK27D184F5D4393D FOREIGN KEY (organisation_fk) REFERENCES organisation (guid))

I don't get it. What am I doing wrong? Shouldn't JPA/Hibernate perform deletes on both the Unit and the Organisation within the same transaction?

Was it helpful?

Solution

A bulk delete query does not load objects into memory and it bypasses any cascade specified on associations.

I would code your delete method as:

public int deleteByGuid(final String guid){
    Organization org = entityManager.find(Organization.class, guid);
    entityManager.remove(org);
}

If you use a Query to do bulk updates, the operation is delegated to the database directly. If you wish to delete child objects, you have to set a DELETE CASCADE trigger at the "database" level.

By loading the object and removing it, Hibernate will trigger the cascade at the "object" level.

More info available at: http://twasink.net/blog/2005/04/differences-in-behaviour-between-hibernate-delete-queries-and-the-old-way/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top