2

So, just last week I asked a question on how to handle many-to-many with extra columns nhibernate. Answer seemed pretty clear, just use the link table and make two many-to-one. However since I'm using Entity Developer to generate my model, I had a problem with that method...

Anyway, I continued my investigation on the many-to-many problem and found that maybe I could create some kind of composite element that would act a lot like a many-to-many, but with an extra property(!)

This would be the new model: Model

The mapping file for User looks like this:

<hibernate-mapping ...>
  <class name="User" table="Users">
    <id name="UId" type="Int32">...</id>
    <property name="UserName" type="String">...</property>

    <set name="Groups" table="UGLinks" inverse="true" generic="true">
      <key>
        <column name="UId" />
      </key>
      <composite-element class="UGLinkExtra">
        <many-to-one name="Groups" class="Group" fetch="join">
          <column name="GId" />
        </many-to-one>
        <property name="Date">
          <column name="Date" not-null="true" />
        </property>
      </composite-element>
    </set>

  </class>
</hibernate-mapping>

So I have this Composite-element that kind of simulates the many-to-many look but with a extra column property.

Let's say I have a User u and a Group g that I want to link. Then it's just a matter of

u.Groups.add(new UGLinkExtra() {Groups = g, Date = DateTime.Now});

And in NHibernate I also see that a link has been added (if I do u.Groups I get a list (of UGLinkExtra) where g is included), however I can't get it to save to the Database! Even when I do session.SaveOrUpdate(u) (or g, I have tried both) it never gets written to the database... Only SQL I see is:

NHibernate: SELECT this_.UId as UId0_0_, this_.UserName as UserName0_0_ FROM Users this_
NHibernate: SELECT this_.GId as GId2_0_, this_.GroupName as GroupName2_0_ FROM Groups this_
Community
  • 1
  • 1
Markus
  • 3,297
  • 4
  • 31
  • 52

1 Answers1

2

The issue here relates to the setting of the <set>. You are telling NHiberante <set name="Groups" ... inverse="true" which means: NHibernate, do not persist the items of this collection. These are so smart, that they will persist themselves...

Which could be usually true, if we use <one-to-many> mapping. But the <composite-element> is totally dependent on its parent collection... to manage its write operations. So change the mapping to inverse="false"

<set name="Groups" table="UGLinks" inverse="false" ...
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Hmm ok, So that works, and then I noticed that I can only add Groups to Users, or the other way around (depending on the `inverse` option). Is there anyway making it possible to add both? – Markus Apr 03 '14 at 06:32
  • I've just tried to explain the same here http://stackoverflow.com/questions/22824660/. My *(only my but very strong)* opinion is, replace the `many-to-many` with a *first-level-citizen* `PairingEntity`. Map it with standard one-to-many and many-to-one elements, and ... just gain and profit. You can experiment here... you can find your way, (I tried as well ;) but once one can change the approach... it will become easier... – Radim Köhler Apr 03 '14 at 06:37
  • Actually I had a problem with my hbm generator (`Entity Developer`) So I couldn't create a link from user-to-user (many-to-many) with the 2 * Many-to-One method. (I needed this: http://stackoverflow.com/a/504845/1140368), but couldn't find a way to generate it. So as this method works fine I plan to use it, just that I can't seem to remove the links again... Any idea? Trying `myUser.Managers.Remove(new UULinkExtra(){Manager = myManager});` – Markus Apr 03 '14 at 14:07
  • Markus, sorry, as I tried to mention... I can hardly help you with many-to-many or some composite keys.. etc. I do not use these. The simple, the powerful. I'd say. But ask new question, maybe someone else... – Radim Köhler Apr 03 '14 at 14:09
  • Ok, so just for the history, it worked with `myUser.Managers.Remove(new UULinkExtra(){Manager = myManager, Date = 2014-04-03});` ie. it had to be the exact object so I have to search for the whole record before I can remove it. – Markus Apr 03 '14 at 14:24