views:

369

answers:

3

Hi,

I am having an issue with many-to-many mapping using NHibernate. Basically I have 2 classes in my object model (Scenario and Skill) mapping to three tables in my database (Scenario, Skill and ScenarioSkill). The ScenarioSkills table just holds the IDs of the SKill and Scenario table (SkillID, ScenarioID).

In the object model a Scenario has a couple of general properties and a list of associated skills (IList) that is obtained from the ScenarioSkills table. There is no associated IList of Scenarios for the Skill object.

The mapping from Scenario and Skill to ScenarioSkill is a many-to-many relationship:

Scenario * --- * ScenarioSkill * --- * Skill

I have mapped out the lists as bags as I believe this is the best option to use from what I have read. The mappings are as follows:

Within the Scenario class

<bag name="Skills" table="ScenarioSkills">
  <key column="ScenarioID" foreign-key="FK_ScenarioSkill_ScenarioID"/>
  <many-to-many class="Domain.Skill, Domain" column="SkillID" />
</bag>

And within the Skill class

<bag name="Scenarios" table="ScenarioSkills" inverse="true" access="noop" cascade="all">
  <key column="SkillID" foreign-key="FK_ScenarioSkill_SkillID" />
  <many-to-many class="Domain.Scenario, Domain" column="ScenarioID" />
</bag>

Everything works fine, except when I try to delete a skill, it cannot do so as there is a reference constraint on the SkillID column of the ScenarioSkill table. Can anyone help me?

I am using NHibernate 2 on an C# asp.net 3.5 web application solution.

+1  A: 

Unless I'm reading the question incorrectly you need to delete the related ScenarioSkills before you delete a Skill or a Scenario. It's pretty straighforward, you just need a custom method to delete the relates ScenarioSkill objects before you delete the parent record.

Do you want it to delete automatically though?

lomaxx
I see what your saying here, and yes I could include a custom method for the delete - I was hoping i could handle it through the mapping using the cascade setting though. Seems to be proving a pain the butt though.
Scozzard
+1  A: 

You'll want to set cascade="all-delete-orphan" on Skills many-to-many linking to ScenarioSkills. Just like it sounds, it will delete the orphaned records and keep that error from popping up.

As a side note, many-to-many's should be used with care. Most many-to-manys contain other information in the relationship and are better mapped as a set of one-to-manys.

EvilRyry
I set cascade="all-delete-orphan" to no avail - still get the reference contraint error on the SkillID column of the ScenarioSkill table...The error is being raised when calling Session.Delete("from Skill s");
Scozzard
+1  A: 

Bit late on the final reply here but this the the mapping I ended up successfully implementing.

In Scenario

<bag name="skills" access="field" schema="OSM" table="ScenarioSkill" cascade="none">
  <key column="ScenarioID"
       foreign-key="FK_ScenarioSkill_Scenario" />

  <!-- Skills can be soft-deleted (groan), so ignore them if they don't 'exist' anymore. -->
  <many-to-many column="SkillID"
                class="DomainModel.Skill, DomainModel"
                foreign-key="FK_ScenarioSkill_Skill"
                where="IsDeleted = 0"/>
</bag>

In Skill

    <!-- inverse end of scenarios -->
<bag name="scenarios" access="field" inverse="true" schema="OSM" table="ScenarioSkill" cascade="none">
  <key column="SkillID"
       foreign-key="FK_ScenarioSkill_Skill" />
  <many-to-many column="ScenarioID"
                class="Scenario"
                foreign-key="FK_ScenarioSkill_Scenario" />
</bag>
Scozzard