Using Hibernate 3.3.2 with annotations 3.4.0.
I'm having trouble with cascade delete orphan not working for one particular setup. Other entities in my code base are working just fine. It's the following that isn't working for some reason. I'm just guessing it may have something to do with the fact that the object being orphaned is off of an entity that is mapped in a one-to-one relationship with another entity. This is pure speculation, but it seems to be the only difference between these set of relationships and the other ones I have which do work.
The following is an abbreviated version of our setup with the likely relevant pieces shown.
There are 3 basic objects, an Account, an Allocation which is mapped one-to-one with the account (Every account has one allocation), and a Holding object, which is mapped as a unidirectional one-to-many Set on the Allocation
Account 1-----1 Allocation 1------N Holding
I can't seem to get hibernate to delete a holding once it's removed (and orphaned) from an Allocation object.
Code:
@Entity
@Table("account")
class Account {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Version
int version;
@OneToOne(targetEntity = Allocation .class, cascade = {CascadeType.ALL})
@Cascade({org.hibernate.annotations.CascadeType.ALL,
org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
@JoinColumn(name="allocation_id")
Allocation allocation;
public Allocation getAllocation() {
return allocation;
}
public void setAllocation(Allocation allocation) {
this.allocation = allocation;
}
// ... other methods etc.
}
@Entity
@Table(name="allocation")
class Allocation {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Version
int version;
@OneToMany(targetEntity = Holding.class, cascade = {CascadeType.ALL}, fetch=FetchType.EAGER)
@Cascade({org.hibernate.annotations.CascadeType.ALL,
org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
@OrderBy("id")
@JoinTable(name = "allocation_to_holding",
joinColumns = { @JoinColumn(name = "allocation_id") },
inverseJoinColumns = { @JoinColumn(name = "holding_id") })
Set<Holding> holdings = new HashSet<Holding>();
public Set<Holding> getHoldings() {
return holdings;
}
public void setHoldings(Set<Holding> holdings) {
this.holdings = holdings;
}
// ... other methods etc.
}
@Entity
@Table(name="holding")
class Holding {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Version
int version;
// ... getters and setters etc.
}
The database schema looks like
Code:
CREATE TABLE `account` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`version` int(11) NOT NULL,
`allocation_id` bigint(20) unsigned default NULL,
...
PRIMARY KEY (`id`),
UNIQUE KEY `UQ___allocation_id` (`allocation_id`),
CONSTRAINT `FK_account__allocation__allocation_id` FOREIGN KEY (`allocation_id`) REFERENCES `allocation` (`id`)
)
CREATE TABLE `allocation` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`version` int(11) NOT NULL,
...
PRIMARY KEY (`id`)
)
CREATE TABLE `holding` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`version` int(11) NOT NULL,
...
PRIMARY KEY (`id`)
)
And the link table between allocation and holding
CREATE TABLE `allocation_to_holding` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`allocation_id` bigint(20) unsigned NOT NULL,
`holding_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UQ_allocation_to_holding__holding_id` (`holding_id`),
KEY `FK_allocation_to_holding__allocation__id` (`allocation_id`),
CONSTRAINT `FK_allocation_to_holding__allocation__id` FOREIGN KEY (`allocation_id`) REFERENCES `allocation` (`id`),
CONSTRAINT `FK_allocation_to_holding__holding__holding_id` FOREIGN KEY (`holding_id`) REFERENCES `holding` (`id`)
)
So I can do the following to add holdings from an allocation
Code:
Holding holding = new Holding(...);
account.getAllocation().getHoldings().add(holding);
account = merge(account)
assertTrue(account.getAllocation().getHoldings().size() == 1);
The following (pseudo) code removes the holding from the allocation, but does not remove the holding from the after it's been orphaned from the allocation holdings collection.
Code:
Holding holding = account.getAllocation().getHoldings().iterator().next();
account.getAllocation().getHoldings().remove(holding);
account = merge(account)
// the following is true
assertTrue(account.getAllocation().getHoldings().size() == 0);
// however, should not find the holding
try {
Holding updatedHolding = get(holding.getId())
fail("updatedHolding should have been deleted.);
} catch (Exception e) {
// exception should be thrown as holding should be deleted from database after becoming orphaned
}
Does anyone have any idea if the one-to-one between account and allocation could be affecting things preventing the delete orphan from working? Or any other ideas?
Thanks,
Skip