This isn't exactly a "gotcha" since it just has to do with writing mappings correctly and thoughfully. But if you are like me, you use CodeSnippets in VisualStudio 2005 to create all your mappings...the carpal tunnel looming upon me after hand coding a million mapping files (zzzz) forced me into working smarter with Snippets.
Anyways, here was my situation. Minor, but took about 15 minutes to debug.
Say two classes, class A and Class B, require a many-to-many relationship with each other. Within Nhibernate, one of the classes needs to be in charge of maintaining the relationship. What this means is just that a decision needs to be made on which class Adds/Removes instances from the collection to persist the relationship correctly. On my project, I am using NHibernate.Generics. I decide that Class A should maintain the relationship so in my Class A constructor I have:
_classBs = new EntityList
(
delegate(ClassB r) { r.ClassAs.Add(this); },
delegate(ClassB r) { r.ClassAs.Add(this); },InitializeOnLazy.Always,OnDuplicate.DoNotAdd);
Now, in my ClassB constructor I have this:
_classAs= new EntityList(
delegate(ClassA t) { t.ClassBs.Add(this); },
delegate(ClassA t) { t.ClassBs.Add(this); });
Then, in my Class A mapping I have this:
<bag name="ClassBs" access="NHibernate.Generics.GenericAccessor, NHibernate.Generics"
lazy="false" cascade="all" table="ClassB_ClassA" inverse="true">
<key column="ClassAId"/>
<many-to-many class="ClassB"
column="ClassBId"/>
</bag>
Then in my Class B mapping I have:
<bag name="ClassAs" access="NHibernate.Generics.GenericAccessor, NHibernate.Generics"
lazy="false" table="ClassB_ClassA" cascade="none">
<key column="ClassBId"/>
<many-to-many class="ClassA"
column="ClassAId"/>
</bag>
In my case, I had forgotten to put the "inverse=true" attribute for the collection of ClassBs in ClassA. This is because I use snippets and more often I am doing one-to-many collections
where the "one" maintains the relationship and so I wouldn't have "inverse-true" expressed on the many-side. This was resulting in duplicate records in my join-table (ClassB_ClassA) because NHibernate wasn't sure WHO was maintaining the relationship...that's what the little "inverse" flag helps establish.