stewchicken 发表于 2007-12-12 17:05

investigate cascade and inverse in deleting many-to-many relation(Hibernate)

cascade and inverse in deleting many-to-many relation

Purpose:
Try to see Hibernate’s behavior when try to delete Person instance based on different
cascade and inverse ‘s combination in Person.hbm.xml


Table:
Person ,   Department , PersonDepartment.

Relation:
Person: PersonDepartment is 1:n
Department: PersonDepartment is 1:n
Person: Department is m:n

Hibernate class:
Person. java
Department.java

Hibernate mapping file:

Person.hbm.xml
Department.xml

Testing DB:
Mysql
Postgre


Testing Data Population:

Person person = new Person();
Department depart = new Department();

person.setFirstname("san");
person.setLastname("zhang");
person.setPersonid(1);
depart.setDepartmentid(10);
depart.setDepartmentname("IT");
person.setDepartments(new HashSet());
person.getDepartments().add(depart);

session.save(depart);
session.save(person);


Deleting Person instance

After testing data population, deleting testing data by following way

Person p = (Person) session.load(Person.class, 1)
session.delete(p);
                       

1)Deleting Person instance with first cascade and inverse combination case .

<set name="departments" table="persondepartment" lazy="true"
                        cascade="none" inverse="false">
                        <key>
                                <column name="personid" />
                        </key>
                        <many-to-many column="departmentid"
                                class="org.hibernate.test.Department" />
                </set>
Result:
Deleting Person will be successful on both mysql and postgre DB.

SQL output on Mysql:
11:17:45,036 DEBUG SQL:401 - delete from persondepartment where personid=?
Hibernate: delete from persondepartment where personid=?
11:17:45,036 DEBUG SQL:401 - delete from person where personid=?
Hibernate: delete from person where personid=?
Conclusion:
Above settingis the best solution for many to many (person: department) because of 2 reasons
a) when we delete person. we dont want to delete department, only breaking linking by deleting persondepartment is enough
b) this solution works on mysql and postgre both


2) Deleting Person instance with second cascade and inverse combination case

<set name="departments" table="persondepartment" lazy="true"
                        cascade="all" inverse="false">
                        <key>
                                <column name="personid" />
                        </key>
                        <many-to-many column="departmentid"
                                class="org.hibernate.test.Department" />
                </set>
Result:
Deleting Person will be successful on mysql and fail on postgre.

SQL output on mysql
11:28:00,868 DEBUG SQL:401 - delete from persondepartment where personid=?
11:28:00,868 DEBUG SQL:401 - delete from department where departmentid=?
11:28:00,868 DEBUG SQL:401 - delete from person where personid=?

Conclusion:
Above setting is not good solution for many to many (person: department),
it will try to delete persondepartment, delete department then delete person,
it works for mysql db but fail on postgre db,
It looks like in mysql deleting sequence is correct, it first deletes middletable, then department,finally person.
mysql can solve deleting sequence correctly,
but on postgre it will fail, because it could not solving deleting sequence correctly.
on postgre,it will first delete department, but department is still refered by child persondepartment table,

I think reason is different db has different interpretation for hibernate's statement.

3) Deleting Person instance with third cascade and inverse combination case

<!-- bi-directional many-to-many association to department -->
                <set name="departments" table="persondepartment" lazy="true"
                        cascade="all" inverse="true">
                        <key>
                                <column name="personid" />
                        </key>
                        <many-to-many column="departmentid"

Result:
Deleting Person will failon both mysql and postgre.
Exception logtrace based on mysql DB

Duplicate key or integrity constraint violation,message from server: "Cannot delete or update a parent row: a foreign key constraint fails (`test/persondepartment`, CONSTRAINT `FK_persondepartment_1` FOREIGN KEY (`departmentid`) REFERENCES `department` (`departmentid`))"
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
                                class="org.hibernate.test.Department" />
                </set>

Conclusion:
It will definately fail, because inverse = true, deleting on persondepartment will never take action, when person is deleted. and cascade is set as all, means when deleting person, it will firstly delete department, but department is referred by persondepartment , which could
not be deleted because of inverse = true, so it will definitely fail on both mysql and postgre.

SQL statement used to create test case on mysql

DROP TABLE IF EXISTS `test`.`department`;
CREATE TABLE`test`.`department` (
`departmentid` int(10) unsigned NOT NULL,
`departmentname` varchar(255) NOT NULL,
PRIMARY KEY(`departmentid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `test`.`person`;
CREATE TABLE`test`.`person` (
`personid` int(10) unsigned NOT NULL default '0',
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) NOT NULL,
PRIMARY KEY(`personid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `test`.`persondepartment`;
CREATE TABLE`test`.`persondepartment` (
`id` int(10) unsigned NOT NULL auto_increment,
`departmentid` int(10) unsigned NOT NULL,
`personid` int(10) unsigned NOT NULL,
PRIMARY KEY(`id`),
KEY `FK_persondepartment_1` (`departmentid`),
KEY `FK_persondepartment_2` (`personid`),
CONSTRAINT `FK_persondepartment_2` FOREIGN KEY (`personid`) REFERENCES `person` (`personid`),
CONSTRAINT `FK_persondepartment_1` FOREIGN KEY (`departmentid`) REFERENCES `department` (`departmentid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
页: [1]
查看完整版本: investigate cascade and inverse in deleting many-to-many relation(Hibernate)