Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate not persisting many-to-many relationship

I'm currently using NHibernate as my data access layer, using Fluent NHibernate to create the mapping files for me. I have two classes, TripItem and TripItemAttributeValue, which have a many-to-many relation between them.

The mapping is as follows:

public class TripItemMap : ClassMap<TripItem2>
{
    public TripItemMap()
    {
        WithTable("TripItemsInt");
        NotLazyLoaded();

        Id(x => x.ID).GeneratedBy.Identity().WithUnsavedValue(0);
        Map(x => x.CreateDate, "CreatedOn").CanNotBeNull();
        Map(x => x.ModifyDate, "LastModified").CanNotBeNull();

        /* snip */

        HasManyToMany<TripItemAttributeValue>(x => x.Attributes).AsBag()
            .WithTableName("TripItems_TripItemAttributeValues_Link")
            .WithParentKeyColumn("TripItemId")
            .WithChildKeyColumn("TripItemAttributeValueId")
            .LazyLoad();
    }
}

public class TripItemAttributeValueMap : ClassMap<TripItemAttributeValue>
{
    public TripItemAttributeValueMap()
    {
        WithTable("TripItemAttributeValues");

        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name).CanNotBeNull();

        HasManyToMany<TripItem2>(x => x.TripItems).AsBag()
            .WithTableName("TripItems_TripItemAttributeValues_Link")
            .WithParentKeyColumn("TripItemAttributeValueId")
            .WithChildKeyColumn("TripItemId")
            .LazyLoad();
    }
}

At some point in my application I fetch existing attributes from the database, add them to tripItem.Attributes, then save the tripItem object. In the end, the TripItems_TripItemAttributeValues_Link never gets any new records, resulting in the relations not being persisted.

If it helps, these are the mapping files generated by Fluent NHibernate for these classes:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain">
  <class name="TripItem2" table="TripItemsInt" xmlns="urn:nhibernate-mapping-2.2" lazy="false">
    <id name="ID" column="ID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="CreateDate" column="CreatedOn" type="DateTime" not-null="true">
      <column name="CreatedOn" />
    </property>
    <property name="ModifyDate" column="LastModified" type="DateTime" not-null="true">
      <column name="LastModified" />
    </property>
    <bag name="Attributes" lazy="true" table="TripItems_TripItemAttributeValues_Link">
      <key column="TripItemId" />
      <many-to-many column="TripItemAttributeValueId" class="ETP.Core.Domain.TripItemAttributeValue, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bag>
  </class>
</hibernate-mapping>

and

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain">
  <class name="TripItemAttributeValue" table="TripItemAttributeValues" xmlns="urn:nhibernate-mapping-2.2">
    <id name="Id" column="Id" type="Int32">
      <generator class="identity" />
    </id>
    <property name="Name" column="Name" length="100" type="String" not-null="true">
      <column name="Name" />
    </property>
    <bag name="TripItems" lazy="true" table="TripItems_TripItemAttributeValues_Link">
      <key column="TripItemAttributeValueId" />
      <many-to-many column="TripItemId" class="ETP.Core.Domain.TripItem2, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bag>
  </class>
</hibernate-mapping>

What am I doing wrong here ?

like image 279
efdee Avatar asked Dec 30 '08 11:12

efdee


2 Answers

@efdee

I was having the same problem and spent almost two days on this. I had a many to many relationship and the link table wasn't being updated either. I'm new to NHibernate, just trying to learn it so take everything I say with a grain of salt.

Well it turned out that it's not Fluent NHibernate, nor the mapping, but me not understanding how NHibernate works with many-to-many. In a many-to-many relationship if collections on both entities aren't populated, NHibernate doesn't persist data to the link table.

Let's say I have this entities in a many-to-many relationship :


partial class Contact
{
   public string ContactName {get; set;}
   public IList Locations {get; set;}

}

partial class Location
{
   public string LocationName {get; set;}
   public string LocationAddress {get;set;}
   public IList Contacts {get;set;}
}

when I add to a location to Contact.Locations, I have to make sure that the contact is also present inside location.Contacts.

so to add a location i have this method inside my Contact class.


public void AddLocation(Location location)
        {
            if (!location.Contacts.Contains(this))
            {
                location.Contacts.Add(this);
            }
            Locations.Add(location);
        }

This seems to have solved my problem, but like I said I'm just picking up NHibernate and learning it, may be there's a better way. If anyone has a better solution, please post.

This is the post that pointed me to check both collections: http://www.coderanch.com/t/217138/Object-Relational-Mapping/link-table-of-ManyToMany-annotation

like image 95
Emmanuel Avatar answered Sep 27 '22 18:09

Emmanuel


Call Session.Flush() or use transaction.

like image 39
Vladimir Kotov Avatar answered Sep 27 '22 18:09

Vladimir Kotov