tags:

views:

721

answers:

1

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?

+1  A: 

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/

Patrick Lafleur
ok that makes perfect sense... however... I have tried it and I get the following Exception:Caused by: javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: Unit.organisation at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614) at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:259)Any ideas? Cheers.
TiGz