What’s the frequency, Kenneth?
Programming with Compassion
An exploration of the joys and frustrations when programming with Microsoft .NET. Taken with the perspective of working in a faith-based ministry, striving to release children from poverty in Jesus' name.
In our latest project, our team made use of NHibernate to act as an ORM (Object-Relational Mapper) and to handle all of our data access work.
In the current phase that we are working on, we’re running into a problem. We can’t get NHibernate to delete a child object in a collection on a parent.
Here’s the basic situation:
We have a Proposal, which has a collection of ProposalMilestones. The ProposalMilestone has a reference to the parent Proposal, as well as a reference to the Milestone that it refers to.
When trying to remove a ProposalMilestone from the collection and flushing the session, NHibernate throws a StaleObjectException.
Here are images of the class diagram for this section and the database schema that applies:
Nothing special about either one. The relationships are as would be expected.
Here are the related mapping files:
Proposal.hbm.xml
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="CIV.Entities" assembly="NHSample" default-access="nosetter.camelcase" default-lazy="false"> <class name="CIV.Entities.Proposal, NHSample" table="Proposal"> <id name="Id" column="ID"> <generator class="guid.comb" /> </id> <version name="Version" column="Version" type="CIV.Entities.Timestamp, NHSample" generated="always" /> <component name="Audit" class="CIV.Entities.Audit, NHSample"> <property name="CreatedBy" column="CreatedBy"/> <property name="CreatedOn" column="CreatedOn" /> <property name="ModifiedBy" column="ModifiedBy" /> <property name="ModifiedOn" column="ModifiedOn" /> </component> <property name="Code" column="Code" /> <property name="Description" column="Description" /> <property name="Name" column="Name" /> <property name="ProposedStartDate" column="ProposedStartDate" /> <bag name="Milestones" table="ProposalMilestone" inverse="true" cascade="all"> <key column="ProposalID" /> <one-to-many class="CIV.Entities.ProposalMilestone, NHSample" /> </bag> </class> </hibernate-mapping>
ProposalMilestone.hbm.xml
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="CIV.Entities" assembly="NHSample" default-access="nosetter.camelcase" default-lazy="false"> <class name="CIV.Entities.ProposalMilestone" table="ProposalMilestone"> <id name="Id" column="ID" unsaved-value="00000000-0000-0000-0000-000000000000"> <generator class="guid.comb" /> </id> <version name="Version" column="Version" type="CIV.Entities.Timestamp, NHSample" generated="always" /> <component name="Audit" class="CIV.Entities.Audit, NHSample"> <property name="CreatedBy" column="CreatedBy"/> <property name="CreatedOn" column="CreatedOn" /> <property name="ModifiedBy" column="ModifiedBy" /> <property name="ModifiedOn" column="ModifiedOn" /> </component> <property name="OriginalDueDate" column="OriginalDueDate" type="DateTime" /> <many-to-one name="Milestone" column="MilestoneID" class="CIV.Entities.Milestone, NHSample"/> <many-to-one name="Proposal" column="ProposalID" not-null="true" class="CIV.Entities.Proposal, NHSample" /> <bag name="Notifications" inverse="true" cascade="all"> <key column="ProposalMilestoneID" /> <one-to-many class="CIV.Entities.Notification, NHSample" /> </bag> </class> </hibernate-mapping>
Milestone
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHSample" namespace="CIV.Entities" default-access="nosetter.camelcase" default-lazy="false"> <class name="CIV.Entities.Milestone, NHSample" table="Milestone"> <id name="Id" column="ID"> <generator class="guid.comb"/> </id> <version name="Version" column="Version" type="CIV.Entities.Timestamp, NHSample" generated="always" /> <component name="Audit" class="CIV.Entities.Audit, NHSample"> <property name="CreatedBy" column="CreatedBy" type="String" /> <property name="CreatedOn" column="CreatedOn" type="DateTime" /> <property name="ModifiedBy" column="ModifiedBy" type="String" /> <property name="ModifiedOn" column="ModifiedOn" type="DateTime" /> </component> <property name="Name" column="Name" type="String" not-null="true" /> <property name="Code" column="Code" type="String" not-null="true" /> <property name="Description" column="Description" type="String" /> </class> </hibernate-mapping>
Any suggestions would be greatly appreciated.
As a side note, I think my relations expressed in the mapping could be better. ProposalMilestone is being treated as an entity right now, but there is no reason (unless NHibernate requires it for the relationships) that it needs to be. I believe Milestone is a value object, but again, it’s being treated as an entity.
Suggestions here would also be appreciated.
Updated (3.29.08)
I did get this problem solved: The final thing that worked for me was putting the optimistic-lock=”false” tag on the collection declaration (Proposal). This avoided updating the Proposal before the collection of ProposalMilestones was updated, which was causing my stale object error.
3 Responses to “Problems With NHibernate”
Leave a Reply
About
This is a collection of the thoughts and ideas of a software developer and solutions architect with Compassion International. Topics of interest include software architecture, design patterns, software factories, team dynamics and the art of computer programming.
Recently
- 3.29.08Eerie…
- 1.13.08Problems With NHibernate
- 1.6.08Making my wife happy
- 9.3.07State of the world today
- 5.27.07What’s a Solutions Architect?
- 5.19.07EntLibContrib Contribution Posted
- 5.18.07NetTiers and SCSF, Part 2
- 5.13.07Introduction: How to use NetTiers in an SCSF Application
- 5.11.07Contribution to EntLib Contrib
- 5.8.07Career Day Wednesday
- 5.7.07So, what’s this all about?
- 5.7.07Patterns&Practices Contrib Projects
Categories
- No categories
For "All flesh is like grass and all its glory like the flower of grass. The grass withers, and the flower falls, but the word of the Lord remains forever." And this word is the good news that was preached to you. (1 Peter 1:24-25)
January 14th, 2008 at 5:51 pm
Hi Mate, One thing you might need to read up on is how collections and inverse collections are handled by NHibernate.
I’m going to have a stab in the dark, but maybe this will help: For your ProposalMilestone to be deleted you might have to delete it from the collection and then delete the ProposalMilestone itself before you call flush. This is because you have a bi-directional relationship between ProposalMilestone and Proposal. When this is the case you need to delete both sides of the relationship for NHibernate to figure out it’s supposed to be deleted.
January 15th, 2008 at 2:32 pm
i take it that wasn’t the problem then? oh well, good luck to you…
January 17th, 2008 at 10:27 pm
Brendan,
that was part of the problem. The final thing that worked for me was putting the optimistic-lock=”false” tag on the collection declaration (Proposal). This avoided updating the Proposal before the collection of ProposalMilestones was updated, which was causing my stale object error.
I had missed that tag in all my trips through the docs, until I was specifically reading for each and every tag on a bag, set, etc.
Thanks for the help and suggestion