tenwit wrote:
Add not-null="true" to the <key> elements that are causing the constraint violation. This ensures that the elements in the various sets are deleted before the entities contains the sets.
I tried this, using various permutations, and am still getting the same constraint violation exception.
Here is what I tried:
Iteration One:
Colors
Code:
<set name="tolerances" table="tblStandardTolerances" cascade="save-update" lazy="false" >
<key column="standardID" not-null="true" />
<many-to-many column="ToleranceID" class="com.xrite.ind.core.tolerances.Tolerance" />
</set>
Tolerances
Code:
<set name="Standards" table="tblStandardTolerances" inverse="true" cascade="none">
<key column="ToleranceID" not-null="true" />
<many-to-many column="StandardID" class="com.xrite.ind.core.Standard"/>
</set>
Iteration Two:
Colors
Code:
<set name="tolerances" table="tblStandardTolerances" cascade="save-update" lazy="false" >
<key column="standardID" />
<many-to-many column="ToleranceID" class="com.xrite.ind.core.tolerances.Tolerance" />
</set>
Tolerances
Code:
<set name="Standards" table="tblStandardTolerances" inverse="true" cascade="none">
<key column="ToleranceID" not-null="true" />
<many-to-many column="StandardID" class="com.xrite.ind.core.Standard"/>
</set>
Iteration Three:
Colors
Code:
<set name="tolerances" table="tblStandardTolerances" cascade="save-update" lazy="false" >
<key column="standardID" not-null="true" />
<many-to-many column="ToleranceID" class="com.xrite.ind.core.tolerances.Tolerance" />
</set>
Tolerances
Code:
<set name="Standards" table="tblStandardTolerances" inverse="true" cascade="none">
<key column="ToleranceID" />
<many-to-many column="StandardID" class="com.xrite.ind.core.Standard"/>
</set>
Unless I misunderstood the use of the
not-null="true" here, it appears that all variations have been tried. I am not sure why this would affect the ordering/cascading of associated rows, deleting them in this case, prior to the actual left or right side table's rows? I would think that the following would be more applicable in this case:
Code:
<set name="Standards" table="tblStandardTolerances" inverse="true" cascade="none">
<key column="ToleranceID" on-delete="cascade"/>
<many-to-many column="StandardID" class="com.xrite.ind.core.Standard"/>
</set>
However,
on-delete="cascade" is NOT allowed for many-to-many relationships. The reason for this is unclear and any Hibernate docs or forum postings I have read which have attempted to explain this design seem to focus on the point that cascading deletes for a many-to-many makes no sense, but I disagree. All I want to do here is remove the associated row first, then one side(rows from one side/table of the many-to-many).
Take for example, the following database:
Table TBLCOLOR
ColorID
--------
1
Table TBLTOLERANCES
ToleranceID
--------------
1
2
3
4
5
Table TBLSTANDARDTOLERANCES
StandardID ToleranceID
------------- -------------
1 1
1 2
1 3
1 4
1 5
When I delete ColorID=1 from TBLCOLOR, first all of the rows from TBLSTANDARDTOLERANCES where StandardID = 1 need to be removed!!! This would be the affect if ON DELETE CASCADE were able to be applied to the foreign key constraint on TBLSTANDARDTOLERANCES which is being violated here! Below is the code generated by way of HBM2DDL
Code:
CREATE TABLE `tblstandardtolerances` (
`standardID` bigint(20) NOT NULL,
`ToleranceID` bigint(20) NOT NULL,
PRIMARY KEY (`ToleranceID`,`standardID`),
KEY `FK9E5C4D01904DBD92` (`ToleranceID`),
KEY `FK9E5C4D016AFB6C9A` (`standardID`),
CONSTRAINT `FK9E5C4D016AFB6C9A` FOREIGN KEY (`standardID`) REFERENCES `tblcolor` (`colorID`),
CONSTRAINT `FK9E5C4D01904DBD92` FOREIGN KEY (`ToleranceID`) REFERENCES `tbltolerance` (`ToleranceID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
This is the desired DDL:
Code:
CREATE TABLE `tblstandardtolerances` (
`standardID` bigint(20) NOT NULL,
`ToleranceID` bigint(20) NOT NULL,
PRIMARY KEY (`ToleranceID`,`standardID`),
KEY `FK9E5C4D01904DBD92` (`ToleranceID`),
KEY `FK9E5C4D016AFB6C9A` (`standardID`),
CONSTRAINT `FK9E5C4D016AFB6C9A` FOREIGN KEY (`standardID`) REFERENCES `tblcolor` (`colorID`) ON DELETE CASCADE,
CONSTRAINT `FK9E5C4D01904DBD92` FOREIGN KEY (`ToleranceID`) REFERENCES `tbltolerance` (`ToleranceID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
After manually dropping the FK9E5C4D016AFB6C9A and re-adding it w/ON DELETE CASCADE, then executing "delete from TBLCOLOR where colorID = 1", it works(as it should!!!).
So, with all this said, why is it so difficult to have Hibernate generate the DDL to do this when you can manually set up your schema w/ordinary DDL creation statements and this all works?
I have proven that the code which creates the
CONSTRAINT `FK9E5C4D016AFB6C9A` FOREIGN KEY (`standardID`) REFERENCES `tblcolor` (`colorID`) is the following mapping in the Tolerances.hbm.xml file:
Code:
<set name="Standards" table="tblStandardTolerances" inverse="true" cascade="none">
<key column="ToleranceID" />
<many-to-many column="StandardID" class="com.xrite.ind.core.Standard"/>
</set>
Is there ANY way in which I can get ON DELETE CASCADE to be added to the foreign key DDL? This would solve my problem.
Here is the exception from the stacktrace:
Code:
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`xcolorqc/tblstandardtolerances`, CONSTRAINT `FK9E5C4D016AFB6C9A` FOREIGN KEY (`standardID`) REFERENCES `tblcolor` (`colorID`))