Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat is the correct way to define many-to-many relationships in NHibernate to allow deletes but avoiding duplicate records
    primarykey
    data
    text
    <p>I've been fighting with an NHibernate set-up for a few days now and just can't figure out the correct way to set out my mapping so it works like I'd expect it to.</p> <p>There's a bit of code to go through before I get to the problems, so apologies in advance for the extra reading.</p> <p>The setup is pretty simple at the moment, with just these tables:</p> <p><strong>Category</strong><br> CategoryId<br> Name</p> <p><strong>Item</strong><br> ItemId<br> Name </p> <p><strong>ItemCategory</strong><br> ItemId<br> CategoryId</p> <p>An item can be in many categories and each category can have many items (simple many-to-many relationship).</p> <p>I have my mapping set out as:</p> <pre><code>&lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="..." namespace="..."&gt; &lt;class name="Category" lazy="true"&gt; &lt;id name="CategoryId" unsaved-value="0"&gt; &lt;generator class="native" /&gt; &lt;/id&gt; &lt;property name="Name" /&gt; &lt;bag name="Items" table="ItemCategory" cascade="save-update" inverse="true" generic="true"&gt; &lt;key column="CategoryId"&gt;&lt;/key&gt; &lt;many-to-many class="Item" column="ItemId"&gt;&lt;/many-to-many&gt; &lt;/bag&gt; &lt;/class&gt; &lt;/hibernate-mapping&gt; &lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="..." namespace="..."&gt; &lt;class name="Item" table="Item" lazy="true"&gt; &lt;id name="ItemId" unsaved-value="0"&gt; &lt;generator class="native" /&gt; &lt;/id&gt; &lt;property name="Name" /&gt; &lt;bag name="Categories" table="ItemCategory" cascade="save-update" generic="true"&gt; &lt;key column="ItemId"&gt;&lt;/key&gt; &lt;many-to-many class="Category" column="CategoryId"&gt;&lt;/many-to-many&gt; &lt;/bag&gt; &lt;/class&gt; &lt;/hibernate-mapping&gt; </code></pre> <p>My methods for adding items to the Item list in Category and Category list in Item set both sides of the relationship.</p> <p>In <strong>Item</strong>: </p> <pre><code> public virtual IList&lt;Category&gt; Categories { get; protected set; } public virtual void AddToCategory(Category category) { if (Categories == null) Categories = new List&lt;Category&gt;(); if (!Categories.Contains(category)) { Categories.Add(category); category.AddItem(this); } } </code></pre> <p>In <strong>Category</strong>: </p> <pre><code> public virtual IList&lt;Item&gt; Items { get; protected set; } public virtual void AddItem(Item item) { if (Items == null) Items = new List&lt;Item&gt;(); if (!Items.Contains(item)) { Items.Add(item); item.AddToCategory(this); } } </code></pre> <p>Now that's out of the way, the issues I'm having are:</p> <ol> <li><p>If I remove the 'inverse="true"' from the Category.Items mapping, I get duplicate entries in the lookup ItemCategory table.</p></li> <li><p>When using 'inverse="true"', I get an error when I try to delete a category as NHibernate doesn't delete the matching record from the lookup table, so fails due to the foreign key constraint.</p></li> <li><p>If I set cascade="all" on the bags, I can delete without error but deleting a Category also deletes all Items in that category.</p></li> </ol> <p>Is there some fundamental problem with the way I have my mapping set up to allow the many-to-many mapping to work as you would expect?</p> <p>By 'the way you would expect', I mean that deletes won't delete anything more than the item being deleted and the corresponding lookup values (leaving the item on the other end of the relationship unaffected) and updates to either collection will update the lookup table with correct and non-duplicate values.</p> <p>Any suggestions would be highly appreciated.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload