I have a simple parent/child tables. Contract is the parent table. Each contract can have multiple units.
Here is my C# class definitions (simplified):
public class Contract : EntityWithIntID
{
public virtual string ContractNum { get; set; }
public virtual IList<Unit> Units { get; protected set; }
public virtual int NumberOfUnits
{
get { return Units.Count; }
}
}
public class Unit : EntityWithIntID
{
<various Unit physical data fields>
}
I’m using FluentNHibernate with AutoMapping. Here is my AutoMapping class:
public static AutoPersistenceModel GetMappings()
{
AutoPersistenceModel returnModel = AutoMap.AssemblyOf<Contract>()
.IgnoreBase(typeof(EntityWithIntID))
.Where(type => type.BaseType == typeof(EntityWithIntID) )
.Conventions.Add(typeof(PluralTableNamesConvention))
.Conventions.Add(typeof(CascadeAllConvention))
.Override<Contract>(map =>map.HasMany(cont =>cont.Units).Inverse())
.Override<Contract>(map=>map.Map(cont => cont.ContractNum).Not.Nullable().Unique())
;
return returnModel;
}
}
Here are the HBM.XML files that Fluent generates:
(for the Units table):
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="InterfaceDB.Unit, InterfaceDB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Units">
<id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Id" />
<generator class="hilo">
<param name="max_lo">10</param>
</generator>
</id>
<!-- physical data property elements removed for brevity -->
</class>
</hibernate-mapping>
(and for the Contracts table):
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="InterfaceDB.Contract, InterfaceDB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Contracts">
<id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Id" />
<generator class="hilo">
<param name="max_lo">10</param>
</generator>
</id>
<property name="ContractNum" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ContractNum" not-null="true" unique="true" />
</property>
<bag cascade="all" inverse="true" name="Units">
<key>
<column name="Contract_id" />
</key>
<one-to-many class="InterfaceDB.Unit, InterfaceDB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>
</class>
</hibernate-mapping>
For my unit testing purposes, I have a “Clear()” method in each of the repositories so I can start with a known empty data base. It simply does a
Session.Delete("from Unit");
followed by a Debug.Assert(Repository.GetCount() == 0);
My problem is that when I do a UnitsRepository.Clear(), I get an NHibernate.ObjectDeleteException: deleted object would be re-saved by cascade (remove deleted object from associations)
I have googled that error, and found a number of articles about it, but nothing suggested seems to work. I have added the “.Inverse()” on the parent mapping. I have tried changing the cascading from “All” to “SaveUpdate” (it was never set to “AllDeleteOrphans”, which some posts cited as the problem.) I’m clearing all the repositories, and I tried wrapping that whole thing in a transaction. I tried adding a flush after the Session.Delete. I tried clearing the parent repository first, then the child. Nothing gets rid of the error.
Any help would be appreciated.
You don’t show it in your mappings but presumably Unit has a reference to its parent Contract. In order to delete a Unit you have to set the reference to the Contract to null and, depending on your mapping, remove it from the Contract’s Units collection.