title: Update entity, delete associations in many to many relationship using Fluent NHibernate
body: <p>I have two entities like this:</p>
  
  <pre><code>public class Service
  {
      public virtual int ServiceId { get; set; }
      public virtual char LayoutCode { get; set; }
      public virtual string ServiceNameEn { get; set; }
      public virtual string ServiceNameTh { get; set; }
      public virtual string ServiceDescEn { get; set; }
      public virtual string ServiceDescTh { get; set; }
      public virtual string ServicePhone { get; set; }
      public virtual byte[] ServiceImage { get; set; }
      public virtual bool Permanent { get; set; }
      public virtual bool Active { get; set; }
      public virtual bool IsAutoAssign { get; set; }
      public virtual DateTime CreatedDatetime { get; set; }
      public virtual DateTime LastUpdatedDatetime { get; set; }
      public virtual string RedirectUrl { get; set; }
      public virtual IList&lt;Reply&gt; Replies { get; set; }
      public virtual IList&lt;Employee&gt; Employees { get; set; }
      public virtual IList&lt;ServicesOfUser&gt; ServicesOfUser { get; set; }
      private IList&lt;Category&gt; _categories = new List&lt;Category&gt;();
      public virtual IEnumerable&lt;Category&gt; Categories
      {
          get
          {
              return _categories;
          }
      }
      public virtual void Add(Category category)
      {
          if (!_categories.Any(x =&gt; x.CategoryId == category.CategoryId))
          {
              _categories.Add(category);
          }
      }
      public virtual void Clear()
      {
          _categories.Clear();
      }
  }
  </code></pre>
  
  <p>and</p>
  
  <pre><code>public class Category
  {
      public virtual int CategoryId { get; set; }
      public virtual string CategoryNameEn { get; set; }
      public virtual string CategoryNameTh { get; set; }
      public virtual string CategoryDescEn { get; set; }
      public virtual string CategoryDescTh { get; set; }
      public virtual byte[] CategoryImage { get; set; }
      public virtual bool Active { get; set; }
      public virtual DateTime CreatedDatetime { get; set; }
      public virtual DateTime LastUpdatedDatetime { get; set; }
      public virtual IList&lt;Service&gt; Services { get; set; }
  }
  </code></pre>
  
  <p>The relationship of these two entities is many-to-many with mappings:</p>
  
  <pre><code>public class ServiceMap : ClassMap&lt;Service&gt;
  {
      public ServiceMap()
      {
          Table("[SERVICES]");
  
          Id(x =&gt; x.ServiceId)
              .GeneratedBy.Identity()
              .Column("service_id")
              .CustomType("int")
              .Access.Property()
              .CustomSqlType("int")
              .Not.Nullable();
          Map(x =&gt; x.LayoutCode)
              .Column("layout_code")
              .CustomType("char")
              .Access.Property()
              .CustomSqlType("char")
              .Length(1)
              .Not.Nullable();
          Map(x =&gt; x.ServiceNameEn)
              .Column("service_name_en")
              .Access.Property()
              .CustomType("string")
              .CustomSqlType("varchar")
              .Length(128)
              .Not.Nullable();
          Map(x =&gt; x.ServiceNameTh)
              .Column("service_name_th")
              .Access.Property()
              .CustomType("string")
              .CustomSqlType("nvarchar")
              .Length(128)
              .Not.Nullable();
          Map(x =&gt; x.ServiceDescEn)
              .Column("service_desc_en")
              .CustomType("string")
              .Access.Property()
              .CustomSqlType("varchar")
              .Length(4000)
              .Nullable();
          Map(x =&gt; x.ServiceDescTh)
              .Column("service_desc_th")
              .CustomType("string")
              .Access.Property()
              .CustomSqlType("nvarchar")
              .Length(4000)
              .Nullable();
          Map(x =&gt; x.ServicePhone)
              .Column("service_phone")
              .Access.Property()
              .CustomType("string")
              .CustomSqlType("nvarchar")
              .Length(50)
              .Nullable();
          Map(x =&gt; x.ServiceImage)
              .Column("service_image")
              .CustomType("BinaryBlob")
              .Access.Property()
              .Generated.Never()
              .CustomSqlType("image")
              .Length(131231)
              .Nullable();
          Map(x =&gt; x.Permanent)
              .Column("permanent")
              .CustomType("bool")
              .Access.Property()
              .CustomSqlType("bit")
              .Not.Nullable();
          Map(x =&gt; x.Active)
              .Column("active")
              .CustomType("bool")
              .Access.Property()
              .CustomSqlType("bit")
              .Not.Nullable();
          Map(x =&gt; x.IsAutoAssign)
              .Column("is_auto_assign")
              .CustomType("bool")
              .Access.Property()
              .CustomSqlType("bit")
              .Not.Nullable();
          Map(x =&gt; x.CreatedDatetime)
              .Column("created_datetime")
              .Access.Property()
              .CustomType("DateTime")
              .CustomSqlType("datetime")
              .Not.Nullable();
          Map(x =&gt; x.LastUpdatedDatetime)
              .Column("last_updated_datetime")
              .Access.Property()
              .CustomType("DateTime")
              .CustomSqlType("datetime")
              .Not.Nullable();
          Map(x =&gt; x.RedirectUrl)
              .Column("redirect_url")
              .Access.Property()
              .CustomType("string")
              .CustomSqlType("nvarchar")
              .Length(213123)
              .Nullable();
          HasMany&lt;ServicesOfUser&gt;(x =&gt; x.ServicesOfUser)
              .AsBag()
              .Cascade.None()
              .LazyLoad()
              .Inverse()
              .KeyColumns.Add("service_id", mapping =&gt; mapping.Name("service_id")
                  .SqlType("int")
                  .Nullable());
          HasMany&lt;Reply&gt;(x =&gt; x.Replies)
              .AsBag()
              .Cascade.None()
              .LazyLoad()
              .Inverse()
              .KeyColumns.Add("send_to_service_id", mapping =&gt; mapping.Name("send_to_service_id")
                  .SqlType("int")
                  .Nullable());
          HasManyToMany&lt;Employee&gt;(x =&gt; x.Employees)
              .AsBag()
              .Cascade.None()
              .LazyLoad()
              .Table("SERVICE_MONITORS")
              .Inverse()
              .ChildKeyColumns.Add("employee_id", mapping =&gt; mapping.Name("employee_id")
                  .SqlType("uniqueidentifier")
                  .Not.Nullable())
              .ParentKeyColumns.Add("service_id", mapping =&gt; mapping.Name("service_id")
                  .SqlType("int")
                  .Not.Nullable());
          HasManyToMany&lt;Category&gt;(x =&gt; x.Categories)
              .AsBag()
              .Access.CamelCaseField(Prefix.Underscore)
              .Cascade.AllDeleteOrphan()
              .Table("SERVICES_IN_CATEGORIES")
              .ChildKeyColumns.Add("category_id", mapping =&gt; mapping.Name("category_id")
                  .SqlType("int")
                  .Not.Nullable())
              .ParentKeyColumns.Add("service_id", mapping =&gt; mapping.Name("service_id")
                  .SqlType("int")
                  .Not.Nullable());
      }
  }
  </code></pre>
  
  <p>And</p>
  
  <pre><code>public class CategoryMap : ClassMap&lt;Category&gt;
  {
      public CategoryMap()
      {
          Table("[SERVICE_CATEGORIES]");
  
          Id(x =&gt; x.CategoryId)
              .GeneratedBy.Identity()
              .Column("category_id")
              .CustomType("int")
              .Access.Property()
              .CustomSqlType("int")
              .Not.Nullable();
          Map(x =&gt; x.CategoryNameEn)
              .Column("category_name_en")
              .CustomType("string")
              .Access.Property()
              .CustomSqlType("varchar")
              .Length(128)
              .Not.Nullable();
          Map(x =&gt; x.CategoryNameTh)
              .Column("category_name_th")
              .CustomType("string")
              .Access.Property()
              .CustomSqlType("nvarchar")
              .Length(128)
              .Not.Nullable();
          Map(x =&gt; x.CategoryDescEn)
              .Column("category_desc_en")
              .CustomType("string")
              .Access.Property()
              .CustomSqlType("varchar")
              .Length(3423423)
              .Not.Nullable();
          Map(x =&gt; x.CategoryDescTh)
              .Column("category_desc_th")
              .CustomType("string")
              .Access.Property()
              .CustomSqlType("nvarchar")
              .Length(3243234)
              .Not.Nullable();
          Map(x =&gt; x.CategoryImage)
              .Column("category_image")
              .CustomType("BinaryBlob")
              .Access.Property()
              .Generated.Never()
              .CustomSqlType("image")
              .Length(131231)
              .Nullable();
          Map(x =&gt; x.Active)
              .Column("active")
              .CustomType("bool")
              .Access.Property()
              .CustomSqlType("bit")
              .Not.Nullable();
          Map(x =&gt; x.CreatedDatetime)
              .Column("created_datetime")
              .Access.Property()
              .CustomType("DateTime")
              .CustomSqlType("datetime")
              .Not.Nullable();
          Map(x =&gt; x.LastUpdatedDatetime)
              .Column("last_updated_datetime")
              .Access.Property()
              .CustomType("DateTime")
              .CustomSqlType("datetime")
              .Not.Nullable();
          HasManyToMany&lt;Service&gt;(x =&gt; x.Services)
              .AsBag()
              .Cascade.AllDeleteOrphan()
              .Inverse()
              .LazyLoad()
              .Table("SERVICES_IN_CATEGORIES")
              .ChildKeyColumns.Add("service_id", mapping =&gt; mapping.Name("service_id")
                  .SqlType("int")
                  .Not.Nullable())
              .ParentKeyColumns.Add("category_id", mapping =&gt; mapping.Name("category_id")
                  .SqlType("int")
                  .Not.Nullable());
      }
  }
  </code></pre>
  
  <p>Coding:</p>
  
  <pre><code>using (unitOfWork = new UnitOfWork(SessionFactory))
  {
      serviceRepo = new ServiceRepo(unitOfWork.Session);
      try
      {
          Service service = new Service();
          if (id != null)
              service = serviceRepo.GetById((int)id);
  
          // set values for service here
  
          IList&lt;Category&gt; categories = new List&lt;Category&gt;();
          // add some categories to service
  
          serviceRepo.Save(service);
          unitOfWork.Commit();
  
          return service;
      }
      catch (Exception ex)
      {
          unitOfWork.Rollback();
          return null;
      }
  }
  </code></pre>
  
  <p>Service is updated, but the association records in join table aren't deleted.</p>
  
  <p>If I add this code below before adding categories to service:</p>
  
  <pre><code>service.Clear();
  </code></pre>
  
  <p>When commit, I get this error message: </p>
  
  <pre><code>not-null property references a null or transient value ilu.src.Entities.Category.CategoryDescEn
  </code></pre>
  
  <p>Full stack trace:</p>
  
  <pre><code>   at NHibernate.Engine.Nullability.CheckNullability(Object[] values, IEntityPersister persister, Boolean isUpdate)
     at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
     at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities)
     at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet transientEntities)
     at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet transientEntities)
     at NHibernate.Engine.CascadingAction.DeleteCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
     at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
     at NHibernate.Event.Default.DefaultDeleteEventListener.CascadeBeforeDelete(IEventSource session, IEntityPersister persister, Object entity, EntityEntry entityEntry, ISet transientEntities)
     at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
     at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities)
     at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet transientEntities)
     at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet transientEntities)
     at NHibernate.Engine.CascadingAction.DeleteCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
     at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
     at NHibernate.Event.Default.DefaultDeleteEventListener.CascadeBeforeDelete(IEventSource session, IEntityPersister persister, Object entity, EntityEntry entityEntry, ISet transientEntities)
     at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
     at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities)
     at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet transientEntities)
     at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet transientEntities)
     at NHibernate.Engine.Cascade.DeleteOrphans(String entityName, IPersistentCollection pc)
     at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
     at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
     at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
     at NHibernate.Event.Default.AbstractFlushingEventListener.CascadeOnFlush(IEventSource session, IEntityPersister persister, Object key, Object anything)
     at NHibernate.Event.Default.AbstractFlushingEventListener.PrepareEntityFlushes(IEventSource session)
     at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event)
     at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
     at NHibernate.Impl.SessionImpl.Flush()
     at NHibernate.Transaction.AdoTransaction.Commit()
     at ilu.src.Common.UnitOfWork.Commit() in D:\Arunsawad\iLertU\ilu\ilu\src\Common\UnitOfWork.cs:line 41
     at ilu.Controllers.AdminController.SaveService(Nullable`1 id, String name, String nameth, String desc, String descth, String phone, String catids, String url, Char layoutcode, Boolean permanent, Boolean active, Boolean autoassign) in D:\Arunsawad\iLertU\ilu\ilu\Controllers\AdminController.cs:line 107
  </code></pre>
  
  <p>Is there anything I'm missing here?</p>
  
  <p>Thank you!</p>