The domain model the DomainObject's audit fields are populated using an AuditInterceptor.
DomainObject Id EstablishDate EstablishId UpdateDate UpdateId Message : DomainObject Description MessageDistributions Distribution : DomainObject BeginEffective EndEffective MessageDistributions MessageDistribution : DomainObject Distribution Message
In this ManyToMany relationship the MessageDistribution also implements the DomainObject in order to use the AuditInterceptor. This keeps me from using the HasManyToMany clause in the FluentNHibernate Mapping.
Here is the mapping code.
public class MessageMap : ClassMap<Message>
{
public MessageMap()
{
WithTable("Message");
Id(x => x.Id).GeneratedBy.Identity().ColumnName("MessageSeq").WithUnsavedValue(0);
Map( x => x.Description ).ColumnName( "SummaryName" );
Map(x => x.EstablishDate);
Map(x => x.EstablishId);
Map(x => x.UpdateDate);
Map(x => x.UpdateId);
HasMany( x => x.MessageDistributions )
.KeyColumnNames.Add( "MessageSeq" )
.Access.AsCamelCaseField( Prefix.Underscore )
.Cascade.All().Inverse();
}
}
public class MessageDistributionMap : ClassMap<MessageDistribution>
{
public MessageDistributionMap()
{
WithTable("MessageDistribution");
Id(x => x.Id).GeneratedBy.Identity().ColumnName("MessageDistributionSeq").WithUnsavedValue(0);
Map(x => x.EstablishDate);
Map(x => x.EstablishId);
Map(x => x.UpdateDate);
Map(x => x.UpdateId);
References(x => x.Message).ColumnName("MessageSeq");
References(x => x.Distribution).ColumnName("DistributionSeq");
}
}
public class DistributionMap : ClassMap<Distribution>
{
public DistributionMap()
{
WithTable("Distribution");
Id(x => x.Id).GeneratedBy.Identity().ColumnName("DistributionSeq").WithUnsavedValue(0);
Map(x => x.BeginEffectiveDate);
Map(x => x.EndEffectiveDate);
Map(x => x.EstablishDate);
Map(x => x.EstablishId);
Map(x => x.UpdateDate);
Map(x => x.UpdateId);
HasMany( x => x.MessageDistributions )
.KeyColumnNames.Add( "DistributionSeq" )
.Access
.AsCamelCaseField( Prefix.Underscore )
.Cascade.All().Inverse();
}
}
Below is a test to implement the above relationship.
[Test]
public void Should_Add_A_Message_To_Existing_Distribution()
{
var desc = "Test message " + DateTime.Now;
var message = new Message { Description = desc, PumpType = 1 };
var distribution = new Distribution
{
BeginEffectiveDate = new DateTime( 2009, 9, 2 ),
EndEffectiveDate = new DateTime( 2009, 9, 10 ),
Priority = 1
};
var messageDistribution = new MessageDistribution { Distribution = distribution };
message.AddMessageDistribution(messageDistribution);
_repository.Save( message );
_repository.Clear();
var retrievedMessage = _repository.GetById(message.Id);
Assert.AreEqual(message, retrievedMessage);
Assert.AreEqual(distribution, retrievedMessage.MessageDistributions[0].Distribution);
}
I execute the test using a test runner and it results in the following error on the line _repository.Save( message );
NHibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Speedway.StoreOperations.CrindMessaging.Core.Domain.Distribution
In my AuditInterceptor I have a
Debug.WriteLine(string.Format("{0} : {1}", propertyNames[i], state[i]));
in the "OnSave and OnFlushDirty" events.
I can see the Message and MessageDistribution are coming through but the Distribution entity never gets touched.
So my question is, is there something wrong with my FluentMapping? Do I have the "Inverse" in the wrong place? Has anyone run across this situation?